| David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 1 | /* | 
|  | 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 | */ | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 19 |  | 
|  | 20 | #include <algorithm> | 
|  | 21 | #include <iostream> | 
|  | 22 |  | 
|  | 23 | #include "TSocketPool.h" | 
|  | 24 |  | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 25 | namespace apache { namespace thrift { namespace transport { | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 26 |  | 
|  | 27 | using namespace std; | 
|  | 28 |  | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 29 | using boost::shared_ptr; | 
|  | 30 |  | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 31 | /** | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 32 | * TSocketPoolServer implementation | 
|  | 33 | * | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 34 | */ | 
|  | 35 | TSocketPoolServer::TSocketPoolServer() | 
|  | 36 | : host_(""), | 
|  | 37 | port_(0), | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 38 | socket_(-1), | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 39 | lastFailTime_(0), | 
|  | 40 | consecutiveFailures_(0) {} | 
|  | 41 |  | 
|  | 42 | /** | 
|  | 43 | * Constructor for TSocketPool server | 
|  | 44 | */ | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 45 | TSocketPoolServer::TSocketPoolServer(const string &host, int port) | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 46 | : host_(host), | 
|  | 47 | port_(port), | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 48 | socket_(-1), | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 49 | lastFailTime_(0), | 
|  | 50 | consecutiveFailures_(0) {} | 
|  | 51 |  | 
|  | 52 | /** | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 53 | * TSocketPool implementation. | 
|  | 54 | * | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 55 | */ | 
|  | 56 |  | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 57 | TSocketPool::TSocketPool() : TSocket(), | 
|  | 58 | numRetries_(1), | 
|  | 59 | retryInterval_(60), | 
|  | 60 | maxConsecutiveFailures_(1), | 
|  | 61 | randomize_(true), | 
|  | 62 | alwaysTryLast_(true) { | 
|  | 63 | } | 
|  | 64 |  | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 65 | TSocketPool::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()) { | 
| boz | 6ded775 | 2007-06-05 22:41:18 +0000 | [diff] [blame] | 74 | GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size"); | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 75 | throw TTransportException(TTransportException::BAD_ARGS); | 
|  | 76 | } | 
|  | 77 |  | 
|  | 78 | for (unsigned int i = 0; i < hosts.size(); ++i) { | 
| dweatherford | d137282 | 2007-10-09 22:57:23 +0000 | [diff] [blame] | 79 | addServer(hosts[i], ports[i]); | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 80 | } | 
|  | 81 | } | 
|  | 82 |  | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 83 | TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(), | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 84 | numRetries_(1), | 
|  | 85 | retryInterval_(60), | 
|  | 86 | maxConsecutiveFailures_(1), | 
|  | 87 | randomize_(true), | 
|  | 88 | alwaysTryLast_(true) | 
|  | 89 | { | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 90 | for (unsigned i = 0; i < servers.size(); ++i) { | 
|  | 91 | addServer(servers[i].first, servers[i].second); | 
|  | 92 | } | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 93 | } | 
|  | 94 |  | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 95 | TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(), | 
| David Reiss | 907ad76 | 2008-03-02 00:25:58 +0000 | [diff] [blame] | 96 | servers_(servers), | 
|  | 97 | numRetries_(1), | 
|  | 98 | retryInterval_(60), | 
|  | 99 | maxConsecutiveFailures_(1), | 
|  | 100 | randomize_(true), | 
|  | 101 | alwaysTryLast_(true) | 
|  | 102 | { | 
|  | 103 | } | 
|  | 104 |  | 
| dweatherford | d137282 | 2007-10-09 22:57:23 +0000 | [diff] [blame] | 105 | TSocketPool::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 |  | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 115 | TSocketPool::~TSocketPool() { | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 116 | 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 | } | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 122 | } | 
|  | 123 |  | 
| dweatherford | d137282 | 2007-10-09 22:57:23 +0000 | [diff] [blame] | 124 | void TSocketPool::addServer(const string& host, int port) { | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 125 | servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port))); | 
| dweatherford | d137282 | 2007-10-09 22:57:23 +0000 | [diff] [blame] | 126 | } | 
|  | 127 |  | 
| David Reiss | 8106ba6 | 2010-03-09 05:19:50 +0000 | [diff] [blame] | 128 | void TSocketPool::addServer(shared_ptr<TSocketPoolServer> &server) { | 
|  | 129 | if (server) { | 
|  | 130 | servers_.push_back(server); | 
|  | 131 | } | 
|  | 132 | } | 
|  | 133 |  | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 134 | void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) { | 
|  | 135 | servers_ = servers; | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) { | 
|  | 139 | servers = servers_; | 
| David Reiss | 907ad76 | 2008-03-02 00:25:58 +0000 | [diff] [blame] | 140 | } | 
|  | 141 |  | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 142 | void TSocketPool::setNumRetries(int numRetries) { | 
|  | 143 | numRetries_ = numRetries; | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | void TSocketPool::setRetryInterval(int retryInterval) { | 
|  | 147 | retryInterval_ = retryInterval; | 
|  | 148 | } | 
|  | 149 |  | 
|  | 150 |  | 
|  | 151 | void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) { | 
|  | 152 | maxConsecutiveFailures_ = maxConsecutiveFailures; | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | void TSocketPool::setRandomize(bool randomize) { | 
|  | 156 | randomize_ = randomize; | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) { | 
|  | 160 | alwaysTryLast_ = alwaysTryLast; | 
|  | 161 | } | 
|  | 162 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 163 | void 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 Reiss | 767c1a9 | 2010-03-09 05:20:28 +0000 | [diff] [blame] | 170 | /** | 
|  | 171 | * This function throws an exception if socket open fails. When socket | 
|  | 172 | * opens fails, the socket in the current server is reset. | 
|  | 173 | */ | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 174 | /* TODO: without apc we ignore a lot of functionality from the php version */ | 
|  | 175 | void TSocketPool::open() { | 
| David Reiss | eed9299 | 2010-03-09 05:19:52 +0000 | [diff] [blame] | 176 |  | 
|  | 177 | unsigned int numServers = servers_.size(); | 
| David Reiss | 767c1a9 | 2010-03-09 05:20:28 +0000 | [diff] [blame] | 178 | if (numServers == 0) { | 
|  | 179 | socket_ = -1; | 
|  | 180 | throw TTransportException(TTransportException::NOT_OPEN); | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | if (isOpen()) { | 
| David Reiss | eed9299 | 2010-03-09 05:19:52 +0000 | [diff] [blame] | 184 | return; | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | if (randomize_ && numServers > 1) { | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 188 | random_shuffle(servers_.begin(), servers_.end()); | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 191 | for (unsigned int i = 0; i < numServers; ++i) { | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 192 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 193 | shared_ptr<TSocketPoolServer> &server = servers_[i]; | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 194 | // Impersonate the server socket | 
|  | 195 | setCurrentServer(server); | 
| David Reiss | f50021a | 2008-02-29 07:33:47 +0000 | [diff] [blame] | 196 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 197 | if (isOpen()) { | 
|  | 198 | // already open means we're done | 
|  | 199 | return; | 
|  | 200 | } | 
|  | 201 |  | 
| David Reiss | eed9299 | 2010-03-09 05:19:52 +0000 | [diff] [blame] | 202 | bool retryIntervalPassed = (server->lastFailTime_ == 0); | 
|  | 203 | bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false; | 
|  | 204 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 205 | if (server->lastFailTime_ > 0) { | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 206 | // The server was marked as down, so check if enough time has elapsed to retry | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 207 | int elapsedTime = time(NULL) - server->lastFailTime_; | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 208 | if (elapsedTime > retryInterval_) { | 
|  | 209 | retryIntervalPassed = true; | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 210 | } | 
|  | 211 | } | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 212 |  | 
|  | 213 | if (retryIntervalPassed || isLastServer) { | 
|  | 214 | for (int j = 0; j < numRetries_; ++j) { | 
|  | 215 | try { | 
|  | 216 | TSocket::open(); | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 217 | } catch (TException e) { | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 218 | string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what(); | 
|  | 219 | GlobalOutput(errStr.c_str()); | 
| David Reiss | 767c1a9 | 2010-03-09 05:20:28 +0000 | [diff] [blame] | 220 | socket_ = -1; | 
|  | 221 | continue; | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 222 | } | 
| David Reiss | 767c1a9 | 2010-03-09 05:20:28 +0000 | [diff] [blame] | 223 |  | 
|  | 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 Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 230 | } | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 231 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 232 | ++server->consecutiveFailures_; | 
|  | 233 | if (server->consecutiveFailures_ > maxConsecutiveFailures_) { | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 234 | // Mark server as down | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 235 | server->consecutiveFailures_ = 0; | 
|  | 236 | server->lastFailTime_ = time(NULL); | 
| David Reiss | 8f3bce4 | 2008-03-18 18:21:52 +0000 | [diff] [blame] | 237 | } | 
| David Reiss | 6d0cccd | 2008-02-28 21:20:12 +0000 | [diff] [blame] | 238 | } | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 239 | } | 
|  | 240 |  | 
| boz | 6ded775 | 2007-06-05 22:41:18 +0000 | [diff] [blame] | 241 | GlobalOutput("TSocketPool::open: all connections failed"); | 
| jsobel | e02e424 | 2007-05-08 17:51:49 +0000 | [diff] [blame] | 242 | throw TTransportException(TTransportException::NOT_OPEN); | 
|  | 243 | } | 
|  | 244 |  | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 245 | void TSocketPool::close() { | 
| David Reiss | 767c1a9 | 2010-03-09 05:20:28 +0000 | [diff] [blame] | 246 | TSocket::close(); | 
|  | 247 | if (currentServer_) { | 
| David Reiss | 1997f10 | 2008-04-29 00:29:41 +0000 | [diff] [blame] | 248 | currentServer_->socket_ = -1; | 
|  | 249 | } | 
|  | 250 | } | 
|  | 251 |  | 
| T Jake Luciani | b5e6221 | 2009-01-31 22:36:20 +0000 | [diff] [blame] | 252 | }}} // apache::thrift::transport |