diff --git a/servers/lloadd/backend.c b/servers/lloadd/backend.c index d0d9b85e2c..89123f9c76 100644 --- a/servers/lloadd/backend.c +++ b/servers/lloadd/backend.c @@ -134,34 +134,57 @@ backend_retry( Backend *b ) int rc, requested; ldap_pvt_thread_mutex_lock( &b->b_mutex ); - /* TODO: timeout regime */ requested = b->b_numconns; if ( !(lload_features & LLOAD_FEATURE_VC) ) { requested += b->b_numbindconns; } if ( b->b_active + b->b_bindavail + b->b_opening < requested ) { - b->b_opening++; - rc = ldap_pvt_thread_pool_submit( - &connection_pool, backend_connect, b ); - /* TODO check we're not shutting down */ - if ( rc ) { - ldap_pvt_thread_mutex_unlock( &b->b_mutex ); - backend_connect( NULL, b ); - return; + if ( b->b_opening > 0 || b->b_failed > 0 ) { + if ( !event_pending( b->b_retry_event, EV_TIMEOUT, NULL ) ) { + Debug( LDAP_DEBUG_CONNS, "backend_retry: " + "scheduling a retry in %d ms\n", + b->b_retry_timeout ); + b->b_opening++; + event_add( b->b_retry_event, &b->b_retry_tv ); + ldap_pvt_thread_mutex_unlock( &b->b_mutex ); + return; + } else { + Debug( LDAP_DEBUG_CONNS, "backend_retry: " + "retry already scheduled\n" ); + } + } else { + Debug( LDAP_DEBUG_CONNS, "backend_retry: " + "scheduling re-connection straight away\n" ); + b->b_opening++; + rc = ldap_pvt_thread_pool_submit( + &connection_pool, backend_connect_task, b ); + /* TODO check we're not shutting down */ + if ( rc ) { + ldap_pvt_thread_mutex_unlock( &b->b_mutex ); + backend_connect( -1, 0, b ); + return; + } } + } else { + Debug( LDAP_DEBUG_CONNS, "backend_retry: " + "no more connections needed for this backend\n" ); } ldap_pvt_thread_mutex_unlock( &b->b_mutex ); } -void * -backend_connect( void *ctx, void *arg ) +void +backend_connect( evutil_socket_t s, short what, void *arg ) { struct evutil_addrinfo hints = {}; Backend *b = arg; char *hostname; ldap_pvt_thread_mutex_lock( &b->b_mutex ); + Debug( LDAP_DEBUG_CONNS, "backend_connect: " + "attempting connection to %s\n", + b->b_host ); + #ifdef LDAP_PF_LOCAL if ( b->b_proto == LDAP_PROTO_IPC ) { struct sockaddr_un addr; @@ -200,7 +223,7 @@ backend_connect( void *ctx, void *arg ) b->b_failed = 0; ldap_pvt_thread_mutex_unlock( &b->b_mutex ); backend_retry( b ); - return NULL; + return; } #endif /* LDAP_PF_LOCAL */ @@ -213,12 +236,18 @@ backend_connect( void *ctx, void *arg ) ldap_pvt_thread_mutex_unlock( &b->b_mutex ); evdns_getaddrinfo( dnsbase, hostname, NULL, &hints, upstream_name_cb, b ); - return NULL; + return; fail: b->b_opening--; b->b_failed++; ldap_pvt_thread_mutex_unlock( &b->b_mutex ); backend_retry( b ); - return (void *)-1; +} + +void * +backend_connect_task( void *ctx, void *arg ) +{ + backend_connect( -1, 0, arg ); + return NULL; } diff --git a/servers/lloadd/daemon.c b/servers/lloadd/daemon.c index fbf8621500..1956ba5f7e 100644 --- a/servers/lloadd/daemon.c +++ b/servers/lloadd/daemon.c @@ -1300,8 +1300,23 @@ slapd_daemon( struct event_base *daemon_base ) } LDAP_STAILQ_FOREACH ( b, &backend, b_next ) { + struct event *retry_event = + evtimer_new( daemon_base, backend_connect, b ); + + if ( !retry_event ) { + Debug( LDAP_DEBUG_ANY, "lloadd: " + "failed to allocate retry event\n" ); + return -1; + } + b->b_retry_event = retry_event; b->b_opening++; - ldap_pvt_thread_pool_submit( &connection_pool, backend_connect, b ); + + rc = ldap_pvt_thread_pool_submit( + &connection_pool, backend_connect_task, b ); + if ( rc ) { + Debug( LDAP_DEBUG_ANY, "failed to schedule backend connection task (%d)\n", rc ); + return rc; + } } lloadd_inited = 1; diff --git a/servers/lloadd/proto-slap.h b/servers/lloadd/proto-slap.h index 6c14fd8ddf..16af23fc83 100644 --- a/servers/lloadd/proto-slap.h +++ b/servers/lloadd/proto-slap.h @@ -40,7 +40,8 @@ struct config_reply_s; /* config.h */ * backend.c */ -LDAP_SLAPD_F (void *) backend_connect( void *ctx, void *arg ); +LDAP_SLAPD_F (void) backend_connect( evutil_socket_t s, short what, void *arg ); +LDAP_SLAPD_F (void *) backend_connect_task( void *ctx, void *arg ); LDAP_SLAPD_F (void) backend_retry( Backend *b ); LDAP_SLAPD_F (Connection *) backend_select( Operation *op );