blob: 1150282bb485dfce166e1c729c79da14cd7997cf [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 Reiss8f3bce42008-03-18 18:21:52 +0000128void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
129 servers_ = servers;
130}
131
132void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
133 servers = servers_;
David Reiss907ad762008-03-02 00:25:58 +0000134}
135
jsobele02e4242007-05-08 17:51:49 +0000136void TSocketPool::setNumRetries(int numRetries) {
137 numRetries_ = numRetries;
138}
139
140void TSocketPool::setRetryInterval(int retryInterval) {
141 retryInterval_ = retryInterval;
142}
143
144
145void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
146 maxConsecutiveFailures_ = maxConsecutiveFailures;
147}
148
149void TSocketPool::setRandomize(bool randomize) {
150 randomize_ = randomize;
151}
152
153void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
154 alwaysTryLast_ = alwaysTryLast;
155}
156
David Reiss1997f102008-04-29 00:29:41 +0000157void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
158 currentServer_ = server;
159 host_ = server->host_;
160 port_ = server->port_;
161 socket_ = server->socket_;
162}
163
jsobele02e4242007-05-08 17:51:49 +0000164/* TODO: without apc we ignore a lot of functionality from the php version */
165void TSocketPool::open() {
166 if (randomize_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000167 random_shuffle(servers_.begin(), servers_.end());
jsobele02e4242007-05-08 17:51:49 +0000168 }
169
David Reiss6d0cccd2008-02-28 21:20:12 +0000170 unsigned int numServers = servers_.size();
171 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000172
David Reiss1997f102008-04-29 00:29:41 +0000173 shared_ptr<TSocketPoolServer> &server = servers_[i];
174 bool retryIntervalPassed = (server->lastFailTime_ == 0);
David Reiss6d0cccd2008-02-28 21:20:12 +0000175 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
jsobele02e4242007-05-08 17:51:49 +0000176
David Reiss1997f102008-04-29 00:29:41 +0000177 // Impersonate the server socket
178 setCurrentServer(server);
David Reissf50021a2008-02-29 07:33:47 +0000179
David Reiss1997f102008-04-29 00:29:41 +0000180 if (isOpen()) {
181 // already open means we're done
182 return;
183 }
184
185 if (server->lastFailTime_ > 0) {
David Reiss6d0cccd2008-02-28 21:20:12 +0000186 // The server was marked as down, so check if enough time has elapsed to retry
David Reiss1997f102008-04-29 00:29:41 +0000187 int elapsedTime = time(NULL) - server->lastFailTime_;
David Reiss6d0cccd2008-02-28 21:20:12 +0000188 if (elapsedTime > retryInterval_) {
189 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000190 }
191 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000192
193 if (retryIntervalPassed || isLastServer) {
194 for (int j = 0; j < numRetries_; ++j) {
195 try {
196 TSocket::open();
197
David Reiss1997f102008-04-29 00:29:41 +0000198 // Copy over the opened socket so that we can keep it persistent
199 server->socket_ = socket_;
200
David Reiss6d0cccd2008-02-28 21:20:12 +0000201 // reset lastFailTime_ is required
David Reiss1997f102008-04-29 00:29:41 +0000202 if (server->lastFailTime_) {
203 server->lastFailTime_ = 0;
David Reiss6d0cccd2008-02-28 21:20:12 +0000204 }
205
206 // success
207 return;
208 } catch (TException e) {
David Reiss1997f102008-04-29 00:29:41 +0000209 string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
210 GlobalOutput(errStr.c_str());
David Reiss6d0cccd2008-02-28 21:20:12 +0000211 // connection failed
212 }
213 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000214
David Reiss1997f102008-04-29 00:29:41 +0000215 ++server->consecutiveFailures_;
216 if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000217 // Mark server as down
David Reiss1997f102008-04-29 00:29:41 +0000218 server->consecutiveFailures_ = 0;
219 server->lastFailTime_ = time(NULL);
David Reiss8f3bce42008-03-18 18:21:52 +0000220 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000221 }
jsobele02e4242007-05-08 17:51:49 +0000222 }
223
boz6ded7752007-06-05 22:41:18 +0000224 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000225 throw TTransportException(TTransportException::NOT_OPEN);
226}
227
David Reiss1997f102008-04-29 00:29:41 +0000228void TSocketPool::close() {
229 if (isOpen()) {
230 TSocket::close();
231 currentServer_->socket_ = -1;
232 }
233}
234
T Jake Lucianib5e62212009-01-31 22:36:20 +0000235}}} // apache::thrift::transport