mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-27 03:20:22 +08:00
Streamlined listener/select/accept handling:
For ITS#2482: added sl_is_mute flag to Listener - when set, the listener is ignored if accept() on a listener fails with EMFILE, set the sl_is_mute flag when removing a connection, if emfile != 0, look for a listener to unmute For ITS#2374: if global_idletimeout is set and there are active sessions, use a timeout on the select() to actively detect idle sessions.
This commit is contained in:
parent
64485f5fe0
commit
8e550fae0c
@ -55,6 +55,7 @@ Listener **slap_listeners = NULL;
|
||||
#define SLAPD_LISTEN 10
|
||||
|
||||
static ber_socket_t wake_sds[2];
|
||||
static int emfile;
|
||||
|
||||
#if defined(NO_THREADS) || defined(HAVE_GNU_PTH)
|
||||
static int waking;
|
||||
@ -251,6 +252,28 @@ void slapd_remove(ber_socket_t s, int wake) {
|
||||
FD_CLR( s, &slap_daemon.sd_readers );
|
||||
FD_CLR( s, &slap_daemon.sd_writers );
|
||||
|
||||
/* If we ran out of file descriptors, we dropped a listener from
|
||||
* the select() loop. Now that we're removing a session from our
|
||||
* control, we can try to resume a dropped listener to use.
|
||||
*/
|
||||
if ( emfile ) {
|
||||
int i;
|
||||
for ( i = 0; slap_listeners[i] != NULL; i++ ) {
|
||||
if ( slap_listeners[i]->sl_sd != AC_SOCKET_INVALID ) {
|
||||
if ( slap_listeners[i]->sl_sd == s ) continue;
|
||||
if ( slap_listeners[i]->sl_is_mute ) {
|
||||
slap_listeners[i]->sl_is_mute = 0;
|
||||
emfile--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Walked the entire list without enabling anything; emfile
|
||||
* counter is stale. Reset it.
|
||||
*/
|
||||
if ( slap_listeners[i] == NULL )
|
||||
emfile = 0;
|
||||
}
|
||||
ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
|
||||
WAKE_LISTENER(wake || slapd_gentle_shutdown == 2);
|
||||
}
|
||||
@ -621,6 +644,7 @@ static int slap_open_listener(
|
||||
}
|
||||
|
||||
l.sl_url.bv_val = NULL;
|
||||
l.sl_is_mute = 0;
|
||||
|
||||
#ifndef HAVE_TLS
|
||||
if( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) {
|
||||
@ -1115,10 +1139,24 @@ slapd_daemon_task(
|
||||
{
|
||||
int l;
|
||||
time_t last_idle_check = 0;
|
||||
struct timeval idle;
|
||||
|
||||
#define SLAPD_IDLE_CHECK_LIMIT 4
|
||||
|
||||
if ( global_idletimeout > 0 ) {
|
||||
last_idle_check = slap_get_time();
|
||||
/* Set the select timeout.
|
||||
* Don't just truncate, preserve the fractions of
|
||||
* seconds to prevent sleeping for zero time.
|
||||
*/
|
||||
idle.tv_sec = global_idletimeout/SLAPD_IDLE_CHECK_LIMIT;
|
||||
idle.tv_usec = global_idletimeout - idle.tv_sec * SLAPD_IDLE_CHECK_LIMIT;
|
||||
idle.tv_usec *= 1000000 / SLAPD_IDLE_CHECK_LIMIT;
|
||||
} else {
|
||||
idle.tv_sec = 0;
|
||||
idle.tv_usec = 0;
|
||||
}
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
|
||||
continue;
|
||||
@ -1202,37 +1240,30 @@ slapd_daemon_task(
|
||||
ber_socket_t nfds;
|
||||
#define SLAPD_EBADF_LIMIT 16
|
||||
int ebadf = 0;
|
||||
int emfile = 0;
|
||||
|
||||
#define SLAPD_IDLE_CHECK_LIMIT 4
|
||||
time_t now;
|
||||
|
||||
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
Sockaddr from;
|
||||
|
||||
struct timeval zero;
|
||||
struct timeval tv;
|
||||
struct timeval *tvp;
|
||||
|
||||
#ifdef LDAP_SYNCREPL
|
||||
struct timeval diff;
|
||||
struct timeval *cat;
|
||||
time_t tdelta = 1;
|
||||
struct re_s* rtask;
|
||||
#endif
|
||||
|
||||
now = slap_get_time();
|
||||
|
||||
if( emfile ) {
|
||||
if( ( global_idletimeout > 0 ) &&
|
||||
difftime( last_idle_check +
|
||||
global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) {
|
||||
connections_timeout_idle( now );
|
||||
|
||||
} else if ( global_idletimeout > 0 ) {
|
||||
if ( difftime( last_idle_check+global_idletimeout/SLAPD_IDLE_CHECK_LIMIT, now ) < 0 ) {
|
||||
connections_timeout_idle( now );
|
||||
last_idle_check = now;
|
||||
}
|
||||
last_idle_check = now;
|
||||
}
|
||||
tv = idle;
|
||||
|
||||
#ifdef SIGHUP
|
||||
if( slapd_gentle_shutdown ) {
|
||||
@ -1258,8 +1289,7 @@ slapd_daemon_task(
|
||||
FD_ZERO( &writefds );
|
||||
FD_ZERO( &readfds );
|
||||
|
||||
zero.tv_sec = 0;
|
||||
zero.tv_usec = 0;
|
||||
at = 0;
|
||||
|
||||
ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
|
||||
|
||||
@ -1282,6 +1312,9 @@ slapd_daemon_task(
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
|
||||
continue;
|
||||
if ( slap_listeners[l]->sl_is_mute )
|
||||
FD_CLR( slap_listeners[l]->sl_sd, &readfds );
|
||||
else
|
||||
if (!FD_ISSET(slap_listeners[l]->sl_sd, &readfds))
|
||||
FD_SET( slap_listeners[l]->sl_sd, &readfds );
|
||||
}
|
||||
@ -1291,10 +1324,15 @@ slapd_daemon_task(
|
||||
#else
|
||||
nfds = dtblsize;
|
||||
#endif
|
||||
if ( global_idletimeout && slap_daemon.sd_nactives )
|
||||
at = 1;
|
||||
|
||||
ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
|
||||
|
||||
at = ldap_pvt_thread_pool_backload(&connection_pool);
|
||||
if ( !at )
|
||||
at = ldap_pvt_thread_pool_backload(&connection_pool);
|
||||
|
||||
tvp = at ? &tv : NULL;
|
||||
|
||||
#ifdef LDAP_SYNCREPL
|
||||
ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
|
||||
@ -1315,28 +1353,21 @@ slapd_daemon_task(
|
||||
ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
|
||||
|
||||
if ( cat != NULL ) {
|
||||
diff.tv_sec = difftime( cat->tv_sec, now );
|
||||
if ( diff.tv_sec == 0 )
|
||||
diff.tv_sec = tdelta;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( HAVE_YIELDING_SELECT ) || defined( NO_THREADS )
|
||||
tvp = NULL;
|
||||
#else
|
||||
tvp = at ? &zero : NULL;
|
||||
#endif
|
||||
|
||||
#ifdef LDAP_SYNCREPL
|
||||
if ( cat != NULL ) {
|
||||
if ( tvp == NULL ) {
|
||||
tvp = &diff;
|
||||
time_t diff = difftime( cat->tv_sec, now );
|
||||
if ( diff == 0 )
|
||||
diff = tdelta;
|
||||
if ( tvp == NULL )
|
||||
tvp = &tv;
|
||||
if ( diff < tv.tv_sec ) {
|
||||
tv.tv_sec = diff;
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
|
||||
if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID ||
|
||||
slap_listeners[l]->sl_is_mute )
|
||||
continue;
|
||||
|
||||
#ifdef NEW_LOGGING
|
||||
@ -1452,7 +1483,7 @@ slapd_daemon_task(
|
||||
|
||||
if ( !FD_ISSET( slap_listeners[l]->sl_sd, &readfds ) )
|
||||
continue;
|
||||
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( slap_listeners[l]->sl_is_udp ) {
|
||||
/* The first time we receive a query, we set this
|
||||
@ -1470,50 +1501,45 @@ slapd_daemon_task(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't need to look at this in the data loops */
|
||||
FD_CLR( slap_listeners[l]->sl_sd, &readfds );
|
||||
FD_CLR( slap_listeners[l]->sl_sd, &writefds );
|
||||
|
||||
s = accept( slap_listeners[l]->sl_sd,
|
||||
(struct sockaddr *) &from, &len );
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
int err = sock_errno();
|
||||
|
||||
if(
|
||||
#ifdef EMFILE
|
||||
if( err == EMFILE ) {
|
||||
emfile++;
|
||||
} else
|
||||
err == EMFILE ||
|
||||
#endif
|
||||
#ifdef ENFILE
|
||||
if( err == ENFILE ) {
|
||||
emfile++;
|
||||
} else
|
||||
err == ENFILE ||
|
||||
#endif
|
||||
0 )
|
||||
{
|
||||
emfile=0;
|
||||
ldap_pvt_thread_mutex_lock( &slap_daemon.sd_mutex );
|
||||
emfile++;
|
||||
/* Stop listening until an existing session closes */
|
||||
slap_listeners[l]->sl_is_mute = 1;
|
||||
ldap_pvt_thread_mutex_unlock( &slap_daemon.sd_mutex );
|
||||
}
|
||||
|
||||
if( emfile < 3 ) {
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG( CONNECTION, ERR,
|
||||
"slapd_daemon_task: accept(%ld) failed errno=%d (%s)\n",
|
||||
(long)slap_listeners[l]->sl_sd,
|
||||
err, sock_errstr(err) );
|
||||
LDAP_LOG( CONNECTION, ERR,
|
||||
"slapd_daemon_task: accept(%ld) failed errno=%d (%s)\n",
|
||||
(long)slap_listeners[l]->sl_sd,
|
||||
err, sock_errstr(err) );
|
||||
#else
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"daemon: accept(%ld) failed errno=%d (%s)\n",
|
||||
(long) slap_listeners[l]->sl_sd, err,
|
||||
sock_errstr(err) );
|
||||
Debug( LDAP_DEBUG_ANY,
|
||||
"daemon: accept(%ld) failed errno=%d (%s)\n",
|
||||
(long) slap_listeners[l]->sl_sd, err,
|
||||
sock_errstr(err) );
|
||||
#endif
|
||||
} else {
|
||||
/* prevent busy loop */
|
||||
# ifdef HAVE_USLEEP
|
||||
if( emfile % 4 == 3 ) usleep( 250 );
|
||||
# else
|
||||
if( emfile % 8 == 7 ) sleep( 1 );
|
||||
# endif
|
||||
}
|
||||
|
||||
ldap_pvt_thread_yield();
|
||||
continue;
|
||||
}
|
||||
emfile = 0;
|
||||
|
||||
#ifndef HAVE_WINSOCK
|
||||
/* make sure descriptor number isn't too great */
|
||||
@ -1768,23 +1794,7 @@ slapd_daemon_task(
|
||||
#else
|
||||
for ( i = 0; i < nfds; i++ ) {
|
||||
int r, w;
|
||||
int is_listener = 0;
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( i == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
/* The listener is the data port. Don't
|
||||
* skip it.
|
||||
*/
|
||||
if (slap_listeners[l]->sl_is_udp) continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( is_listener ) {
|
||||
continue;
|
||||
}
|
||||
r = FD_ISSET( i, &readfds );
|
||||
w = FD_ISSET( i, &writefds );
|
||||
if ( r || w ) {
|
||||
@ -1814,7 +1824,6 @@ slapd_daemon_task(
|
||||
#endif
|
||||
{
|
||||
ber_socket_t wd;
|
||||
int is_listener = 0;
|
||||
#ifdef HAVE_WINSOCK
|
||||
wd = writefds.fd_array[i];
|
||||
#else
|
||||
@ -1824,18 +1833,6 @@ slapd_daemon_task(
|
||||
wd = i;
|
||||
#endif
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( i == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (slap_listeners[l]->sl_is_udp) continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( is_listener ) {
|
||||
continue;
|
||||
}
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG( CONNECTION, DETAIL2,
|
||||
"slapd_daemon_task: write active on %d\n", wd, 0, 0 );
|
||||
@ -1864,8 +1861,6 @@ slapd_daemon_task(
|
||||
#endif
|
||||
{
|
||||
ber_socket_t rd;
|
||||
int is_listener = 0;
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
rd = readfds.fd_array[i];
|
||||
#else
|
||||
@ -1875,19 +1870,6 @@ slapd_daemon_task(
|
||||
rd = i;
|
||||
#endif
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( rd == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (slap_listeners[l]->sl_is_udp) continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( is_listener ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG( CONNECTION, DETAIL2,
|
||||
"slapd_daemon_task: read activity on %d\n", rd, 0, 0 );
|
||||
|
@ -2143,6 +2143,7 @@ struct slap_listener {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
int sl_is_udp; /* UDP listener is also data port */
|
||||
#endif
|
||||
int sl_is_mute; /* Listening is temporarily disabled */
|
||||
ber_socket_t sl_sd;
|
||||
Sockaddr sl_sa;
|
||||
#define sl_addr sl_sa.sa_in_addr
|
||||
|
Loading…
Reference in New Issue
Block a user