blob: af7303bd067e071581c97af49906bf2a130bd507 [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
60TSocketPool::TSocketPool(const 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
dweatherfordd1372822007-10-09 22:57:23 +000072TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
73 numRetries_(1),
74 retryInterval_(60),
75 maxConsecutiveFailures_(1),
76 randomize_(true),
77 alwaysTryLast_(true)
78{
79 addServer(host, port);
80}
81
jsobele02e4242007-05-08 17:51:49 +000082TSocketPool::~TSocketPool() {
83 close();
84}
85
dweatherfordd1372822007-10-09 22:57:23 +000086void TSocketPool::addServer(const string& host, int port) {
David Reiss6d0cccd2008-02-28 21:20:12 +000087 servers_.push_back(TSocketPoolServer(host, port));
dweatherfordd1372822007-10-09 22:57:23 +000088}
89
jsobele02e4242007-05-08 17:51:49 +000090void TSocketPool::setNumRetries(int numRetries) {
91 numRetries_ = numRetries;
92}
93
94void TSocketPool::setRetryInterval(int retryInterval) {
95 retryInterval_ = retryInterval;
96}
97
98
99void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
100 maxConsecutiveFailures_ = maxConsecutiveFailures;
101}
102
103void TSocketPool::setRandomize(bool randomize) {
104 randomize_ = randomize;
105}
106
107void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
108 alwaysTryLast_ = alwaysTryLast;
109}
110
111/* TODO: without apc we ignore a lot of functionality from the php version */
112void TSocketPool::open() {
113 if (randomize_) {
114 std::random_shuffle(servers_.begin(), servers_.end());
115 }
116
David Reiss6d0cccd2008-02-28 21:20:12 +0000117 unsigned int numServers = servers_.size();
118 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000119
David Reiss6d0cccd2008-02-28 21:20:12 +0000120 TSocketPoolServer &server = servers_[i];
121 bool retryIntervalPassed = (server.lastFailTime_ == 0);
122 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
jsobele02e4242007-05-08 17:51:49 +0000123
David Reiss6d0cccd2008-02-28 21:20:12 +0000124 if (server.lastFailTime_ > 0) {
125 // The server was marked as down, so check if enough time has elapsed to retry
126 int elapsedTime = time(NULL) - server.lastFailTime_;
127 if (elapsedTime > retryInterval_) {
128 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000129 }
130 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000131
132 if (retryIntervalPassed || isLastServer) {
133 for (int j = 0; j < numRetries_; ++j) {
134 try {
135 TSocket::open();
136
137 // reset lastFailTime_ is required
138 if (server.lastFailTime_) {
139 server.lastFailTime_ = 0;
140 }
141
142 // success
143 return;
144 } catch (TException e) {
145 // connection failed
146 }
147 }
148 }
149
150 ++server.consecutiveFailures_;
151 if (server.consecutiveFailures_ > maxConsecutiveFailures_) {
152 // Mark server as down
153 server.consecutiveFailures_ = 0;
154 server.lastFailTime_ = time(NULL);
155 }
jsobele02e4242007-05-08 17:51:49 +0000156 }
157
boz6ded7752007-06-05 22:41:18 +0000158 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000159 throw TTransportException(TTransportException::NOT_OPEN);
160}
161
162}}} // facebook::thrift::transport