From 3a71bddbc4fefec1f6a6476d4f1b97afc23f58b5 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 27 Mar 2003 03:35:46 +0000 Subject: [PATCH] ITS#2389 - added conn_max_pending/auth config keywords to cap the number of outstanding requests on a connection. Set rate limits for request execution: no connection can have more than maxthreads/2 ops executing at once. a connection that is write-blocked will not execute any new ops. queued ops must drain before any new ops can execute. If the queue exceeds the max_pending limit, the connection is closed. ...also fixed a bug where a connection was not marked active if it never received a Bind. --- servers/slapd/config.c | 77 ++++++++++++++++++++++++++++++++++++++ servers/slapd/connection.c | 44 +++++++++++++++------- servers/slapd/proto-slap.h | 2 + servers/slapd/slap.h | 3 ++ 4 files changed, 112 insertions(+), 14 deletions(-) diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 21ef05484b..8951f40664 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -63,6 +63,9 @@ struct berval global_schemandn = { 0, NULL }; ber_len_t sockbuf_max_incoming = SLAP_SB_MAX_INCOMING_DEFAULT; ber_len_t sockbuf_max_incoming_auth= SLAP_SB_MAX_INCOMING_AUTH; +int slap_conn_max_pending = SLAP_CONN_MAX_PENDING_DEFAULT; +int slap_conn_max_pending_auth = SLAP_CONN_MAX_PENDING_AUTH; + char *slapd_pid_file = NULL; char *slapd_args_file = NULL; @@ -332,6 +335,80 @@ read_config( const char *fname, int depth ) sockbuf_max_incoming_auth = max; + /* set conn pending max */ + } else if ( strcasecmp( cargv[0], "conn_max_pending" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing max in \"conn_max_pending " + "\" line\n", fname, lineno, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"conn_max_pending \" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + max = atol( cargv[1] ); + + if( max < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: invalid max value (%ld) in " + "\"conn_max_pending \" line.\n", + fname, lineno, max ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"conn_max_pending \" line.\n", + fname, lineno, max ); +#endif + + return( 1 ); + } + + slap_conn_max_pending = max; + + /* set conn pending max authenticated */ + } else if ( strcasecmp( cargv[0], "conn_max_pending_auth" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing max in \"conn_max_pending_auth " + "\" line\n", fname, lineno, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"conn_max_pending_auth \" line\n", + fname, lineno, 0 ); +#endif + + return( 1 ); + } + + max = atol( cargv[1] ); + + if( max < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: invalid max value (%ld) in " + "\"conn_max_pending_auth \" line.\n", + fname, lineno, max ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"conn_max_pending_auth \" line.\n", + fname, lineno, max ); +#endif + + return( 1 ); + } + + slap_conn_max_pending_auth = max; + /* default search base */ } else if ( strcasecmp( cargv[0], "defaultSearchBase" ) == 0 ) { if ( cargc < 2 ) { diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 84aea37b9b..538f3721ce 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1303,6 +1303,7 @@ connection_input( ber_len_t len; ber_int_t msgid; BerElement *ber; + int rc; #ifdef LDAP_CONNECTIONLESS Sockaddr peeraddr; char *cdn = NULL; @@ -1430,7 +1431,6 @@ connection_input( #endif #ifdef LDAP_CONNECTIONLESS if (conn->c_is_udp) { - int rc; if ( cdn ) { ber_str2bv( cdn, 0, 1, &op->o_dn ); @@ -1468,9 +1468,22 @@ connection_input( } #endif /* LDAP_CONNECTIONLESS */ + rc = 0; + + /* Don't process requests when the conn is in the middle of a + * Bind, or if it's closing. Also, don't let any single conn + * use up all the available threads, and don't execute if we're + * currently blocked on output. And don't execute if there are + * already pending ops, let them go first. + */ if ( conn->c_conn_state == SLAP_C_BINDING - || conn->c_conn_state == SLAP_C_CLOSING ) + || conn->c_conn_state == SLAP_C_CLOSING + || conn->c_n_ops_executing >= connection_pool_max/2 + || conn->c_n_ops_pending + || conn->c_writewaiter) { + int max = conn->c_dn.bv_len ? slap_conn_max_pending_auth + : slap_conn_max_pending; #ifdef NEW_LOGGING LDAP_LOG( CONNECTION, INFO, "connection_input: conn %lu deferring operation\n", @@ -1480,18 +1493,13 @@ connection_input( #endif conn->c_n_ops_pending++; LDAP_STAILQ_INSERT_TAIL( &conn->c_pending_ops, op, o_next ); - + if ( conn->c_n_ops_pending > max ) { + rc = -1; + } else { + rc = 1; + } } else { conn->c_n_ops_executing++; - /* Don't allow any single conn to soak up all of the - * available threads - */ - if (conn->c_n_ops_executing > connection_pool_max/2) { - ber_socket_t sd; - - ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd ); - slapd_clr_read( sd, 0 ); - } connection_op_activate( op ); } @@ -1503,7 +1511,7 @@ connection_input( #endif assert( conn->c_struct_state == SLAP_C_USED ); - return 0; + return rc; } static int @@ -1566,12 +1574,15 @@ connection_resched( Connection *conn ) return 0; } - if( conn->c_conn_state != SLAP_C_ACTIVE ) { + if( conn->c_conn_state != SLAP_C_ACTIVE || conn->c_writewaiter ) { /* other states need different handling */ return 0; } while ((op = LDAP_STAILQ_FIRST( &conn->c_pending_ops )) != NULL) { + if ( conn->c_n_ops_executing > connection_pool_max/2 ) { + break; + } LDAP_STAILQ_REMOVE_HEAD( &conn->c_pending_ops, o_next ); LDAP_STAILQ_NEXT(op, o_next) = NULL; /* pending operations should not be marked for abandonment */ @@ -1610,6 +1621,11 @@ static int connection_op_activate( Operation *op ) op->o_protocol = op->o_conn->c_protocol ? op->o_conn->c_protocol : LDAP_VERSION3; } + if (op->o_conn->c_conn_state == SLAP_C_INACTIVE + && op->o_protocol > LDAP_VERSION2) { + op->o_conn->c_conn_state = SLAP_C_ACTIVE; + } + op->o_connid = op->o_conn->c_connid; LDAP_STAILQ_INSERT_TAIL( &op->o_conn->c_ops, op, o_next ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 94e0606ce5..6c5a613349 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1147,6 +1147,8 @@ LDAP_SLAPD_V(unsigned) num_subordinates; LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming; LDAP_SLAPD_V (ber_len_t) sockbuf_max_incoming_auth; +LDAP_SLAPD_V (int) slap_conn_max_pending; +LDAP_SLAPD_V (int) slap_conn_max_pending_auth; LDAP_SLAPD_V (slap_mask_t) global_restrictops; LDAP_SLAPD_V (slap_mask_t) global_allows; diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 76c3989071..f09916f2b0 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -81,6 +81,9 @@ LDAP_BEGIN_DECL #define SLAP_SB_MAX_INCOMING_DEFAULT ((1<<18) - 1) #define SLAP_SB_MAX_INCOMING_AUTH ((1<<24) - 1) +#define SLAP_CONN_MAX_PENDING_DEFAULT 100 +#define SLAP_CONN_MAX_PENDING_AUTH 1000 + #define SLAP_TEXT_BUFLEN (256) /* psuedo error code indicating abandoned operation */ -- 2.39.5