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:
Howard Chu 2003-05-15 13:10:52 +00:00
parent 64485f5fe0
commit 8e550fae0c
2 changed files with 87 additions and 104 deletions

View File

@ -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 );

View File

@ -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