]> git.sur5r.net Git - openldap/commitdiff
Streamlined listener/select/accept handling:
authorHoward Chu <hyc@openldap.org>
Thu, 15 May 2003 13:10:52 +0000 (13:10 +0000)
committerHoward Chu <hyc@openldap.org>
Thu, 15 May 2003 13:10:52 +0000 (13:10 +0000)
  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.

servers/slapd/daemon.c
servers/slapd/slap.h

index 73e7479155edd7624864e73916f0ba4ebcc8d069..22f9edf57a385879c0d638541235599261160255 100644 (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) );
-#endif
-                               } else {
-                                       /* prevent busy loop */
-#  ifdef HAVE_USLEEP
-                                       if( emfile % 4 == 3 ) usleep( 250 );
-#  else
-                                       if( emfile % 8 == 7 ) sleep( 1 );
-#  endif
-                               }
-
+                               Debug( LDAP_DEBUG_ANY,
+                                       "daemon: accept(%ld) failed errno=%d (%s)\n",
+                                       (long) slap_listeners[l]->sl_sd, err,
+                                       sock_errstr(err) );
+#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 );
index 9037d88696e5441c105ae739dfa27fba4cf5d846..38f0a4ca6b97745be11056d4b13b73f5fab85fc5 100644 (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