From 1ea81ce9b08d554a6256611adc5089184692ab71 Mon Sep 17 00:00:00 2001 From: boz Date: Mon, 14 May 2007 23:04:33 +0000 Subject: [PATCH] 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 --- lib/cpp/src/transport/TServerSocket.cpp | 31 ++++++++++++++++++++++--- lib/cpp/src/transport/TServerSocket.h | 5 ++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/cpp/src/transport/TServerSocket.cpp b/lib/cpp/src/transport/TServerSocket.cpp index 3b11e9da..e942a67f 100644 --- a/lib/cpp/src/transport/TServerSocket.cpp +++ b/lib/cpp/src/transport/TServerSocket.cpp @@ -25,6 +25,8 @@ TServerSocket::TServerSocket(int port) : acceptBacklog_(1024), sendTimeout_(0), recvTimeout_(0), + retryLimit_(0), + retryDelay_(0), intSock1_(-1), intSock2_(-1) {} @@ -34,6 +36,8 @@ TServerSocket::TServerSocket(int port, int sendTimeout, int recvTimeout) : acceptBacklog_(1024), sendTimeout_(sendTimeout), recvTimeout_(recvTimeout), + retryLimit_(0), + retryDelay_(0), intSock1_(-1), intSock2_(-1) {} @@ -49,6 +53,14 @@ void TServerSocket::setRecvTimeout(int recvTimeout) { 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 @@ void TServerSocket::listen() { 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 @@ shared_ptr TServerSocket::acceptImpl() { if (recvTimeout_ > 0) { client->setRecvTimeout(recvTimeout_); } - + return client; } diff --git a/lib/cpp/src/transport/TServerSocket.h b/lib/cpp/src/transport/TServerSocket.h index edd25106..8d76fef7 100644 --- a/lib/cpp/src/transport/TServerSocket.h +++ b/lib/cpp/src/transport/TServerSocket.h @@ -30,6 +30,9 @@ class TServerSocket : public TServerTransport { void setSendTimeout(int sendTimeout); void setRecvTimeout(int recvTimeout); + void setRetryLimit(int retryLimit); + void setRetryDelay(int retryDelay); + void listen(); void close(); @@ -44,6 +47,8 @@ class TServerSocket : public TServerTransport { int acceptBacklog_; int sendTimeout_; int recvTimeout_; + int retryLimit_; + int retryDelay_; int intSock1_; int intSock2_; -- 2.17.1