blob: 160c5a3c67f52fa720f27a8a77e38f065a87ec30 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
jsobele02e4242007-05-08 17:51:49 +000019
20#include <algorithm>
21#include <iostream>
22
23#include "TSocketPool.h"
24
T Jake Lucianib5e62212009-01-31 22:36:20 +000025namespace apache { namespace thrift { namespace transport {
jsobele02e4242007-05-08 17:51:49 +000026
27using namespace std;
28
David Reiss8f3bce42008-03-18 18:21:52 +000029using boost::shared_ptr;
30
jsobele02e4242007-05-08 17:51:49 +000031/**
David Reiss6d0cccd2008-02-28 21:20:12 +000032 * TSocketPoolServer implementation
33 *
David Reiss6d0cccd2008-02-28 21:20:12 +000034 */
35TSocketPoolServer::TSocketPoolServer()
36 : host_(""),
37 port_(0),
David Reiss1997f102008-04-29 00:29:41 +000038 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000039 lastFailTime_(0),
40 consecutiveFailures_(0) {}
41
42/**
43 * Constructor for TSocketPool server
44 */
David Reiss8f3bce42008-03-18 18:21:52 +000045TSocketPoolServer::TSocketPoolServer(const string &host, int port)
David Reiss6d0cccd2008-02-28 21:20:12 +000046 : host_(host),
47 port_(port),
David Reiss1997f102008-04-29 00:29:41 +000048 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000049 lastFailTime_(0),
50 consecutiveFailures_(0) {}
51
52/**
jsobele02e4242007-05-08 17:51:49 +000053 * TSocketPool implementation.
54 *
jsobele02e4242007-05-08 17:51:49 +000055 */
56
David Reiss8f3bce42008-03-18 18:21:52 +000057TSocketPool::TSocketPool() : TSocket(),
58 numRetries_(1),
59 retryInterval_(60),
60 maxConsecutiveFailures_(1),
61 randomize_(true),
62 alwaysTryLast_(true) {
63}
64
jsobele02e4242007-05-08 17:51:49 +000065TSocketPool::TSocketPool(const vector<string> &hosts,
66 const vector<int> &ports) : TSocket(),
67 numRetries_(1),
68 retryInterval_(60),
69 maxConsecutiveFailures_(1),
70 randomize_(true),
71 alwaysTryLast_(true)
72{
73 if (hosts.size() != ports.size()) {
boz6ded7752007-06-05 22:41:18 +000074 GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
jsobele02e4242007-05-08 17:51:49 +000075 throw TTransportException(TTransportException::BAD_ARGS);
76 }
77
78 for (unsigned int i = 0; i < hosts.size(); ++i) {
dweatherfordd1372822007-10-09 22:57:23 +000079 addServer(hosts[i], ports[i]);
jsobele02e4242007-05-08 17:51:49 +000080 }
81}
82
David Reiss8f3bce42008-03-18 18:21:52 +000083TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
jsobele02e4242007-05-08 17:51:49 +000084 numRetries_(1),
85 retryInterval_(60),
86 maxConsecutiveFailures_(1),
87 randomize_(true),
88 alwaysTryLast_(true)
89{
David Reiss6d0cccd2008-02-28 21:20:12 +000090 for (unsigned i = 0; i < servers.size(); ++i) {
91 addServer(servers[i].first, servers[i].second);
92 }
jsobele02e4242007-05-08 17:51:49 +000093}
94
David Reiss8f3bce42008-03-18 18:21:52 +000095TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
David Reiss907ad762008-03-02 00:25:58 +000096 servers_(servers),
97 numRetries_(1),
98 retryInterval_(60),
99 maxConsecutiveFailures_(1),
100 randomize_(true),
101 alwaysTryLast_(true)
102{
103}
104
dweatherfordd1372822007-10-09 22:57:23 +0000105TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
106 numRetries_(1),
107 retryInterval_(60),
108 maxConsecutiveFailures_(1),
109 randomize_(true),
110 alwaysTryLast_(true)
111{
112 addServer(host, port);
113}
114
jsobele02e4242007-05-08 17:51:49 +0000115TSocketPool::~TSocketPool() {
David Reiss1997f102008-04-29 00:29:41 +0000116 vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
117 vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
118 for (; iter != iterEnd; ++iter) {
119 setCurrentServer(*iter);
120 TSocketPool::close();
121 }
jsobele02e4242007-05-08 17:51:49 +0000122}
123
dweatherfordd1372822007-10-09 22:57:23 +0000124void TSocketPool::addServer(const string& host, int port) {
David Reiss8f3bce42008-03-18 18:21:52 +0000125 servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
dweatherfordd1372822007-10-09 22:57:23 +0000126}
127
David Reiss8106ba62010-03-09 05:19:50 +0000128void TSocketPool::addServer(shared_ptr<TSocketPoolServer> &server) {
129 if (server) {
130 servers_.push_back(server);
131 }
132}
133
David Reiss8f3bce42008-03-18 18:21:52 +0000134void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
135 servers_ = servers;
136}
137
138void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
139 servers = servers_;
David Reiss907ad762008-03-02 00:25:58 +0000140}
141
jsobele02e4242007-05-08 17:51:49 +0000142void TSocketPool::setNumRetries(int numRetries) {
143 numRetries_ = numRetries;
144}
145
146void TSocketPool::setRetryInterval(int retryInterval) {
147 retryInterval_ = retryInterval;
148}
149
150
151void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
152 maxConsecutiveFailures_ = maxConsecutiveFailures;
153}
154
155void TSocketPool::setRandomize(bool randomize) {
156 randomize_ = randomize;
157}
158
159void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
160 alwaysTryLast_ = alwaysTryLast;
161}
162
David Reiss1997f102008-04-29 00:29:41 +0000163void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
164 currentServer_ = server;
165 host_ = server->host_;
166 port_ = server->port_;
167 socket_ = server->socket_;
168}
169
David Reiss767c1a92010-03-09 05:20:28 +0000170/**
171 * This function throws an exception if socket open fails. When socket
172 * opens fails, the socket in the current server is reset.
173 */
jsobele02e4242007-05-08 17:51:49 +0000174/* TODO: without apc we ignore a lot of functionality from the php version */
175void TSocketPool::open() {
David Reisseed92992010-03-09 05:19:52 +0000176
177 unsigned int numServers = servers_.size();
David Reiss767c1a92010-03-09 05:20:28 +0000178 if (numServers == 0) {
179 socket_ = -1;
180 throw TTransportException(TTransportException::NOT_OPEN);
181 }
182
183 if (isOpen()) {
David Reisseed92992010-03-09 05:19:52 +0000184 return;
185 }
186
187 if (randomize_ && numServers > 1) {
David Reiss8f3bce42008-03-18 18:21:52 +0000188 random_shuffle(servers_.begin(), servers_.end());
jsobele02e4242007-05-08 17:51:49 +0000189 }
190
David Reiss6d0cccd2008-02-28 21:20:12 +0000191 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000192
David Reiss1997f102008-04-29 00:29:41 +0000193 shared_ptr<TSocketPoolServer> &server = servers_[i];
David Reiss1997f102008-04-29 00:29:41 +0000194 // Impersonate the server socket
195 setCurrentServer(server);
David Reissf50021a2008-02-29 07:33:47 +0000196
David Reiss1997f102008-04-29 00:29:41 +0000197 if (isOpen()) {
198 // already open means we're done
199 return;
200 }
201
David Reisseed92992010-03-09 05:19:52 +0000202 bool retryIntervalPassed = (server->lastFailTime_ == 0);
203 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
204
David Reiss1997f102008-04-29 00:29:41 +0000205 if (server->lastFailTime_ > 0) {
David Reiss6d0cccd2008-02-28 21:20:12 +0000206 // The server was marked as down, so check if enough time has elapsed to retry
David Reiss1997f102008-04-29 00:29:41 +0000207 int elapsedTime = time(NULL) - server->lastFailTime_;
David Reiss6d0cccd2008-02-28 21:20:12 +0000208 if (elapsedTime > retryInterval_) {
209 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000210 }
211 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000212
213 if (retryIntervalPassed || isLastServer) {
214 for (int j = 0; j < numRetries_; ++j) {
215 try {
216 TSocket::open();
David Reiss6d0cccd2008-02-28 21:20:12 +0000217 } catch (TException e) {
David Reiss1997f102008-04-29 00:29:41 +0000218 string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
219 GlobalOutput(errStr.c_str());
David Reiss767c1a92010-03-09 05:20:28 +0000220 socket_ = -1;
221 continue;
David Reiss6d0cccd2008-02-28 21:20:12 +0000222 }
David Reiss767c1a92010-03-09 05:20:28 +0000223
224 // Copy over the opened socket so that we can keep it persistent
225 server->socket_ = socket_;
226 // reset lastFailTime_ is required
227 server->lastFailTime_ = 0;
228 // success
229 return;
David Reiss6d0cccd2008-02-28 21:20:12 +0000230 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000231
David Reiss1997f102008-04-29 00:29:41 +0000232 ++server->consecutiveFailures_;
233 if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000234 // Mark server as down
David Reiss1997f102008-04-29 00:29:41 +0000235 server->consecutiveFailures_ = 0;
236 server->lastFailTime_ = time(NULL);
David Reiss8f3bce42008-03-18 18:21:52 +0000237 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000238 }
jsobele02e4242007-05-08 17:51:49 +0000239 }
240
boz6ded7752007-06-05 22:41:18 +0000241 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000242 throw TTransportException(TTransportException::NOT_OPEN);
243}
244
David Reiss1997f102008-04-29 00:29:41 +0000245void TSocketPool::close() {
David Reiss767c1a92010-03-09 05:20:28 +0000246 TSocket::close();
247 if (currentServer_) {
David Reiss1997f102008-04-29 00:29:41 +0000248 currentServer_->socket_ = -1;
249 }
250}
251
T Jake Lucianib5e62212009-01-31 22:36:20 +0000252}}} // apache::thrift::transport