Round robin for backends.

Several threads calling backend_select might reset current_backend to a
different place, there are two options to deal with that:
- just let the last rotation win (the current approach)
- detect whether first == current_backend and only replace then

Not sure which one is more useful, going with the simpler.
This commit is contained in:
Ondřej Kuzník 2017-05-10 16:07:11 +01:00 committed by Ondřej Kuzník
parent e65cd38787
commit 53015aa4cb
5 changed files with 28 additions and 4 deletions

View file

@ -93,21 +93,31 @@ fail:
Connection *
backend_select( Operation *op )
{
Backend *b;
Backend *b, *first, *next;
ldap_pvt_thread_mutex_lock( &backend_mutex );
first = b = current_backend;
ldap_pvt_thread_mutex_unlock( &backend_mutex );
if ( !first ) {
return NULL;
}
/* TODO: Two runs, one with trylock, then one actually locked if we don't
* find anything? */
LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) {
do {
struct ConnSt *head;
Connection *c;
ldap_pvt_thread_mutex_lock( &b->b_mutex );
next = LDAP_CIRCLEQ_LOOP_NEXT( &backend, b, b_next );
if ( b->b_max_pending && b->b_n_ops_executing >= b->b_max_pending ) {
Debug( LDAP_DEBUG_CONNS, "backend_select: "
"backend %s too busy\n",
b->b_bindconf.sb_uri.bv_val );
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
b = next;
continue;
}
@ -130,10 +140,15 @@ backend_select( Operation *op )
/*
* Round-robin step:
* Rotate the queue to put this connection at the end.
* Rotate the queue to put this connection at the end, same for
* the backend.
*/
LDAP_CIRCLEQ_MAKE_TAIL( head, c, c_next );
ldap_pvt_thread_mutex_lock( &backend_mutex );
current_backend = next;
ldap_pvt_thread_mutex_unlock( &backend_mutex );
b->b_n_ops_executing++;
c->c_n_ops_executing++;
CONNECTION_UNLOCK_INCREF(c);
@ -145,7 +160,9 @@ backend_select( Operation *op )
ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
}
ldap_pvt_thread_mutex_unlock( &b->b_mutex );
}
b = next;
} while ( b != first );
return NULL;
}

View file

@ -113,6 +113,8 @@ static ConfigDriver config_tls_config;
#endif
slap_b_head backend = LDAP_CIRCLEQ_HEAD_INITIALIZER(backend);
ldap_pvt_thread_mutex_t backend_mutex;
Backend *current_backend = NULL;
enum {
CFG_ACL = 1,

View file

@ -1313,6 +1313,7 @@ slapd_daemon( struct event_base *daemon_base )
}
}
current_backend = LDAP_CIRCLEQ_FIRST( &backend );
LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) {
struct event *retry_event =
evtimer_new( daemon_base, backend_connect, b );

View file

@ -98,6 +98,8 @@ slap_init( int mode, const char *name )
LDAP_STAILQ_INIT( &slapd_rq.task_list );
LDAP_STAILQ_INIT( &slapd_rq.run_list );
ldap_pvt_thread_mutex_init( &backend_mutex );
break;
default:

View file

@ -124,6 +124,8 @@ extern int slap_inet4or6;
typedef LDAP_CIRCLEQ_HEAD(BeSt, Backend) slap_b_head;
LDAP_SLAPD_V (slap_b_head) backend;
LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) backend_mutex;
LDAP_SLAPD_V (Backend *) current_backend;
LDAP_SLAPD_V (int) slapMode;
#define SLAP_UNDEFINED_MODE 0x0000