diff --git a/AUTHORS b/AUTHORS index 65a50407..d3b594e6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,6 +54,7 @@ Tamara Kustarova Taras Shpot Tero Marttila Terry Wilson +Thijs Terlouw Toralf Wittner Vitaly Mayatskikh diff --git a/doc/zmq_getsockopt.txt b/doc/zmq_getsockopt.txt index 132e7b34..ad50d387 100644 --- a/doc/zmq_getsockopt.txt +++ b/doc/zmq_getsockopt.txt @@ -261,10 +261,11 @@ Option value unit:: milliseconds Default value:: -1 (infinite) Applicable socket types:: all + ZMQ_RECONNECT_IVL: Retrieve reconnection interval ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The 'ZMQ_RECONNECT_IVL' option shall retrieve the reconnection interval for the -specified 'socket'. The reconnection interval is the maximum period 0MQ shall +The 'ZMQ_RECONNECT_IVL' option shall retrieve the initial reconnection interval +for the specified 'socket'. The reconnection interval is the period 0MQ shall wait between attempts to reconnect disconnected peers when using connection-oriented transports. @@ -278,6 +279,24 @@ Default value:: 100 Applicable socket types:: all, only for connection-oriented transports +ZMQ_RECONNECT_IVL_MAX: Retrieve maximum reconnection interval +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The 'ZMQ_RECONNECT_IVL_MAX' option shall retrieve the maximum reconnection +interval for the specified 'socket'. This is the maximum period 0MQ shall wait +between attempts to reconnect. On each reconnect attempt, the previous interval +shall be doubled untill ZMQ_RECONNECT_IVL_MAX is reached. This allows for +exponential backoff strategy. Default value means no exponential backoff is +performed and reconnect interval calculations are only based on ZMQ_RECONNECT_IVL. + +NOTE: Values less than ZMQ_RECONNECT_IVL will be ignored. + +[horizontal] +Option value type:: int +Option value unit:: milliseconds +Default value:: 0 (only use ZMQ_RECONNECT_IVL) +Applicable socket types:: all, only for connection-oriented transport + + ZMQ_BACKLOG: Retrieve maximum length of the queue of outstanding connections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The 'ZMQ_BACKLOG' option shall retrieve the maximum length of the queue of diff --git a/doc/zmq_setsockopt.txt b/doc/zmq_setsockopt.txt index 58f04b31..c3428505 100644 --- a/doc/zmq_setsockopt.txt +++ b/doc/zmq_setsockopt.txt @@ -272,9 +272,9 @@ Applicable socket types:: all ZMQ_RECONNECT_IVL: Set reconnection interval ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The 'ZMQ_RECONNECT_IVL' option shall set the reconnection interval for the -specified 'socket'. The reconnection interval is the maximum period 0MQ shall -wait between attempts to reconnect disconnected peers when using +The 'ZMQ_RECONNECT_IVL' option shall set the initial reconnection interval for +the specified 'socket'. The reconnection interval is the period 0MQ +shall wait between attempts to reconnect disconnected peers when using connection-oriented transports. NOTE: The reconnection interval may be randomized by 0MQ to prevent @@ -287,6 +287,24 @@ Default value:: 100 Applicable socket types:: all, only for connection-oriented transports +ZMQ_RECONNECT_IVL_MAX: Set maximum reconnection interval +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The 'ZMQ_RECONNECT_IVL_MAX' option shall set the maximum reconnection interval +for the specified 'socket'. This is the maximum period 0MQ shall wait between +attempts to reconnect. On each reconnect attempt, the previous interval shall be +doubled untill ZMQ_RECONNECT_IVL_MAX is reached. This allows for exponential +backoff strategy. Default value means no exponential backoff is performed and +reconnect interval calculations are only based on ZMQ_RECONNECT_IVL. + +NOTE: Values less than ZMQ_RECONNECT_IVL will be ignored. + +[horizontal] +Option value type:: int +Option value unit:: milliseconds +Default value:: 0 (only use ZMQ_RECONNECT_IVL) +Applicable socket types:: all, only for connection-oriented transports + + ZMQ_BACKLOG: Set maximum length of the queue of outstanding connections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The 'ZMQ_BACKLOG' option shall set the maximum length of the queue of diff --git a/include/zmq.h b/include/zmq.h index 74b89873..e56b5ed7 100644 --- a/include/zmq.h +++ b/include/zmq.h @@ -203,7 +203,8 @@ ZMQ_EXPORT int zmq_term (void *context); #define ZMQ_RECONNECT_IVL 18 #define ZMQ_BACKLOG 19 #define ZMQ_RECOVERY_IVL_MSEC 20 /* opt. recovery time, reconcile in 3.x */ - +#define ZMQ_RECONNECT_IVL_MAX 21 + /* Send/recv options. */ #define ZMQ_NOBLOCK 1 #define ZMQ_SNDMORE 2 diff --git a/src/options.cpp b/src/options.cpp index ae350599..c6d57607 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -37,6 +37,7 @@ zmq::options_t::options_t () : type (-1), linger (-1), reconnect_ivl (100), + reconnect_ivl_max (0), backlog (100), requires_in (false), requires_out (false), @@ -161,6 +162,18 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, reconnect_ivl = *((int*) optval_); return 0; + case ZMQ_RECONNECT_IVL_MAX: + if (optvallen_ != sizeof (int)) { + errno = EINVAL; + return -1; + } + if (*((int*) optval_) < 0) { + errno = EINVAL; + return -1; + } + reconnect_ivl_max = *((int*) optval_); + return 0; + case ZMQ_BACKLOG: if (optvallen_ != sizeof (int)) { errno = EINVAL; @@ -297,6 +310,15 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) *optvallen_ = sizeof (int); return 0; + case ZMQ_RECONNECT_IVL_MAX: + if (*optvallen_ < sizeof (int)) { + errno = EINVAL; + return -1; + } + *((int*) optval_) = reconnect_ivl_max; + *optvallen_ = sizeof (int); + return 0; + case ZMQ_BACKLOG: if (*optvallen_ < sizeof (int)) { errno = EINVAL; diff --git a/src/options.hpp b/src/options.hpp index e6df5059..38c69823 100644 --- a/src/options.hpp +++ b/src/options.hpp @@ -59,8 +59,12 @@ namespace zmq // Linger time, in milliseconds. int linger; - // Interval between attempts to reconnect, in milliseconds. + // Minimum interval between attempts to reconnect, in milliseconds. + // Default 100ms int reconnect_ivl; + // Maximum interval between attempts to reconnect, in milliseconds. + // Default 0 (unused) + int reconnect_ivl_max; // Maximum backlog for pending connections. int backlog; diff --git a/src/zmq_connecter.cpp b/src/zmq_connecter.cpp index 8a6d89a1..d2638ac7 100644 --- a/src/zmq_connecter.cpp +++ b/src/zmq_connecter.cpp @@ -40,10 +40,11 @@ zmq::zmq_connecter_t::zmq_connecter_t (class io_thread_t *io_thread_, io_object_t (io_thread_), handle_valid (false), wait (wait_before_connect), - session (session_) + session (session_), + current_reconnect_ivl(options.reconnect_ivl) { - int rc = tcp_connecter.set_address (protocol_, address_); - zmq_assert (rc == 0); + int rc = tcp_connecter.set_address (protocol_, address_); + zmq_assert (rc == 0); } zmq::zmq_connecter_t::~zmq_connecter_t () @@ -54,21 +55,10 @@ zmq::zmq_connecter_t::~zmq_connecter_t () rm_fd (handle); } -int zmq::zmq_connecter_t::get_reconnect_ivl () -{ -#if defined ZMQ_HAVE_WINDOWS - return (options.reconnect_ivl + (((int) GetCurrentProcessId () * 13) - % options.reconnect_ivl)); -#else - return (options.reconnect_ivl + (((int) getpid () * 13) - % options.reconnect_ivl)); -#endif -} - void zmq::zmq_connecter_t::process_plug () { if (wait) - add_timer (get_reconnect_ivl (), reconnect_timer_id); + add_reconnect_timer(); else start_connecting (); } @@ -91,7 +81,7 @@ void zmq::zmq_connecter_t::out_event () if (fd == retired_fd) { tcp_connecter.close (); wait = true; - add_timer (get_reconnect_ivl (), reconnect_timer_id); + add_reconnect_timer(); return; } @@ -140,5 +130,36 @@ void zmq::zmq_connecter_t::start_connecting () // Handle any other error condition by eventual reconnect. wait = true; - add_timer (get_reconnect_ivl (), reconnect_timer_id); + add_reconnect_timer(); +} + +void zmq::zmq_connecter_t::add_reconnect_timer() +{ + add_timer (get_new_reconnect_ivl(), reconnect_timer_id); +} + +int zmq::zmq_connecter_t::get_new_reconnect_ivl () +{ +#if defined ZMQ_HAVE_WINDOWS + int pid = (int) GetCurrentProcessId (); +#else + int pid = (int) getpid (); +#endif + + // The new interval is the current interval + random value. + int this_interval = current_reconnect_ivl + + ((pid * 13) % options.reconnect_ivl); + + // Only change the current reconnect interval if the maximum reconnect + // interval was set and if it's larger than the reconnect interval. + if (options.reconnect_ivl_max > 0 && + options.reconnect_ivl_max > options.reconnect_ivl) { + + // Calculate the next interval + current_reconnect_ivl = current_reconnect_ivl * 2; + if(current_reconnect_ivl >= options.reconnect_ivl_max) { + current_reconnect_ivl = options.reconnect_ivl_max; + } + } + return this_interval; } diff --git a/src/zmq_connecter.hpp b/src/zmq_connecter.hpp index 060f5c9d..ef2cd1aa 100644 --- a/src/zmq_connecter.hpp +++ b/src/zmq_connecter.hpp @@ -55,8 +55,13 @@ namespace zmq // Internal function to start the actual connection establishment. void start_connecting (); - // Internal function to return the reconnect backoff delay. - int get_reconnect_ivl (); + // Internal function to add a reconnect timer + void add_reconnect_timer(); + + // Internal function to return a reconnect backoff delay. + // Will modify the current_reconnect_ivl used for next call + // Returns the currently used interval + int get_new_reconnect_ivl (); // Actual connecting socket. tcp_connecter_t tcp_connecter; @@ -74,6 +79,9 @@ namespace zmq // Reference to the session we belong to. class session_t *session; + // Current reconnect ivl, updated for backoff strategy + int current_reconnect_ivl; + zmq_connecter_t (const zmq_connecter_t&); const zmq_connecter_t &operator = (const zmq_connecter_t&); };