THRIFT: configurable retry settings for bind
Summary: SO_REUSEADDR doesn't always work, and some of my servers have
expensive init routines that I really want to run before it becomes available
to services, so I want thrift to retry the bind several times at varied
intervals before giving up
Reviewed By: slee
Test Plan: running a service in GDB with no problems binding, with another
service bound to the port for all the retries, another service bound to the
port for only some of the retries
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665109 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/transport/TServerSocket.cpp b/lib/cpp/src/transport/TServerSocket.cpp
index 3b11e9d..e942a67 100644
--- a/lib/cpp/src/transport/TServerSocket.cpp
+++ b/lib/cpp/src/transport/TServerSocket.cpp
@@ -25,6 +25,8 @@
acceptBacklog_(1024),
sendTimeout_(0),
recvTimeout_(0),
+ retryLimit_(0),
+ retryDelay_(0),
intSock1_(-1),
intSock2_(-1) {}
@@ -34,6 +36,8 @@
acceptBacklog_(1024),
sendTimeout_(sendTimeout),
recvTimeout_(recvTimeout),
+ retryLimit_(0),
+ retryDelay_(0),
intSock1_(-1),
intSock2_(-1) {}
@@ -49,6 +53,14 @@
recvTimeout_ = recvTimeout;
}
+void TServerSocket::setRetryLimit(int retryLimit) {
+ retryLimit_ = retryLimit;
+}
+
+void TServerSocket::setRetryDelay(int retryDelay) {
+ retryDelay_ = retryDelay;
+}
+
void TServerSocket::listen() {
int sv[2];
if (-1 == socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
@@ -113,13 +125,26 @@
throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed");
}
- // Bind to a port
+ // prepare the port information
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port_);
addr.sin_addr.s_addr = INADDR_ANY;
- if (-1 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
+
+ // we may want to try to bind more than once, since SO_REUSEADDR doesn't
+ // always seem to work. The client can configure the retry variables.
+ int retries = 0;
+ do {
+ if (0 == bind(serverSocket_, (struct sockaddr *)&addr, sizeof(addr))) {
+ break;
+ }
+
+ // use short circuit evaluation here to only sleep if we need to
+ } while ((retries++ < retryLimit_) && (sleep(retryDelay_) == 0));
+
+ // throw an error if we failed to bind properly
+ if (retries > retryLimit_) {
char errbuf[1024];
sprintf(errbuf, "TServerSocket::listen() BIND %d", port_);
perror(errbuf);
@@ -203,7 +228,7 @@
if (recvTimeout_ > 0) {
client->setRecvTimeout(recvTimeout_);
}
-
+
return client;
}