From: Howard Chu Date: Thu, 27 Mar 2003 04:04:06 +0000 (+0000) Subject: Fix ITS#2389, sync with HEAD X-Git-Tag: OPENLDAP_REL_ENG_2_1_17~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d6e1c6e410098ff71d99d892faa6b829459780c;p=thirdparty%2Fopenldap.git Fix ITS#2389, sync with HEAD --- diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 020450c839..8c93db6bd2 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_pending_max" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing max in \"conn_pending_max " + "\" line\n", fname, lineno, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"conn_pending_max \" 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_pending_max \" line.\n", + fname, lineno, max ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"conn_pending_max \" line.\n", + fname, lineno, max ); +#endif + + return( 1 ); + } + + slap_conn_max_pending = max; + + /* set conn pending max authenticated */ + } else if ( strcasecmp( cargv[0], "conn_pending_max_auth" ) == 0 ) { + long max; + if ( cargc < 2 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing max in \"conn_pending_max_auth " + "\" line\n", fname, lineno, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing max in \"conn_pending_max_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_pending_max_auth \" line.\n", + fname, lineno, max ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: invalid max value (%ld) in " + "\"conn_pending_max_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 005496fdd9..538f3721ce 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -55,18 +55,13 @@ static Connection* connection_get( ber_socket_t s ); static int connection_input( Connection *c ); static void connection_close( Connection *c ); -static int connection_op_activate( Connection *conn, Operation *op ); +static int connection_op_activate( Operation *op ); static int connection_resched( Connection *conn ); static void connection_abandon( Connection *conn ); static void connection_destroy( Connection *c ); static ldap_pvt_thread_start_t connection_operation; -struct co_arg { - Connection *co_conn; - Operation *co_op; -}; - /* * Initialize connection management infrastructure. */ @@ -887,18 +882,18 @@ static void * connection_operation( void *ctx, void *arg_v ) { int rc; - struct co_arg *arg = arg_v; - ber_tag_t tag = arg->co_op->o_tag; + Operation *op = arg_v; + ber_tag_t tag = op->o_tag; #ifdef SLAPD_MONITOR ber_tag_t oldtag = tag; #endif /* SLAPD_MONITOR */ - Connection *conn = arg->co_conn; + Connection *conn = op->o_conn; ldap_pvt_thread_mutex_lock( &num_ops_mutex ); num_ops_initiated++; ldap_pvt_thread_mutex_unlock( &num_ops_mutex ); - arg->co_op->o_threadctx = ctx; + op->o_threadctx = ctx; if( conn->c_sasl_bind_in_progress && tag != LDAP_REQ_BIND ) { #ifdef NEW_LOGGING @@ -910,7 +905,7 @@ connection_operation( void *ctx, void *arg_v ) "error: SASL bind in progress (tag=%ld).\n", (long) tag, 0, 0 ); #endif - send_ldap_result( conn, arg->co_op, + send_ldap_result( conn, op, rc = LDAP_OPERATIONS_ERROR, NULL, "SASL bind in progress", NULL, NULL ); goto operations_error; @@ -919,52 +914,52 @@ connection_operation( void *ctx, void *arg_v ) switch ( tag ) { case LDAP_REQ_BIND: INCR_OP(num_ops_initiated_, SLAP_OP_BIND); - rc = do_bind( conn, arg->co_op ); + rc = do_bind( conn, op ); break; case LDAP_REQ_UNBIND: INCR_OP(num_ops_initiated_, SLAP_OP_UNBIND); - rc = do_unbind( conn, arg->co_op ); + rc = do_unbind( conn, op ); break; case LDAP_REQ_ADD: INCR_OP(num_ops_initiated_, SLAP_OP_ADD); - rc = do_add( conn, arg->co_op ); + rc = do_add( conn, op ); break; case LDAP_REQ_DELETE: INCR_OP(num_ops_initiated_, SLAP_OP_DELETE); - rc = do_delete( conn, arg->co_op ); + rc = do_delete( conn, op ); break; case LDAP_REQ_MODRDN: INCR_OP(num_ops_initiated_, SLAP_OP_MODRDN); - rc = do_modrdn( conn, arg->co_op ); + rc = do_modrdn( conn, op ); break; case LDAP_REQ_MODIFY: INCR_OP(num_ops_initiated_, SLAP_OP_MODIFY); - rc = do_modify( conn, arg->co_op ); + rc = do_modify( conn, op ); break; case LDAP_REQ_COMPARE: INCR_OP(num_ops_initiated_, SLAP_OP_COMPARE); - rc = do_compare( conn, arg->co_op ); + rc = do_compare( conn, op ); break; case LDAP_REQ_SEARCH: INCR_OP(num_ops_initiated_, SLAP_OP_SEARCH); - rc = do_search( conn, arg->co_op ); + rc = do_search( conn, op ); break; case LDAP_REQ_ABANDON: INCR_OP(num_ops_initiated_, SLAP_OP_ABANDON); - rc = do_abandon( conn, arg->co_op ); + rc = do_abandon( conn, op ); break; case LDAP_REQ_EXTENDED: INCR_OP(num_ops_initiated_, SLAP_OP_EXTENDED); - rc = do_extended( conn, arg->co_op ); + rc = do_extended( conn, op ); break; default: @@ -976,8 +971,8 @@ connection_operation( void *ctx, void *arg_v ) Debug( LDAP_DEBUG_ANY, "unknown LDAP request 0x%lx\n", tag, 0, 0 ); #endif - arg->co_op->o_tag = LBER_ERROR; - send_ldap_disconnect( conn, arg->co_op, + op->o_tag = LBER_ERROR; + send_ldap_disconnect( conn, op, LDAP_PROTOCOL_ERROR, "unknown LDAP request" ); rc = -1; break; @@ -1028,12 +1023,12 @@ operations_error: ldap_pvt_thread_mutex_unlock( &num_ops_mutex ); #ifdef LDAP_EXOP_X_CANCEL - if ( arg->co_op->o_cancel == SLAP_CANCEL_REQ ) { - arg->co_op->o_cancel = LDAP_TOO_LATE; + if ( op->o_cancel == SLAP_CANCEL_REQ ) { + op->o_cancel = LDAP_TOO_LATE; } - while ( arg->co_op->o_cancel != SLAP_CANCEL_NONE && - arg->co_op->o_cancel != SLAP_CANCEL_DONE ) + while ( op->o_cancel != SLAP_CANCEL_NONE && + op->o_cancel != SLAP_CANCEL_DONE ) { ldap_pvt_thread_yield(); } @@ -1044,33 +1039,28 @@ operations_error: conn->c_n_ops_executing--; conn->c_n_ops_completed++; - LDAP_STAILQ_REMOVE( &conn->c_ops, arg->co_op, slap_op, o_next); - LDAP_STAILQ_NEXT(arg->co_op, o_next) = NULL; + LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); + LDAP_STAILQ_NEXT(op, o_next) = NULL; #if defined(LDAP_CLIENT_UPDATE) || defined(LDAP_SYNC) - if ( arg->co_op->o_cancel == SLAP_CANCEL_ACK ) + if ( op->o_cancel == SLAP_CANCEL_ACK ) goto co_op_free; #endif #ifdef LDAP_CLIENT_UPDATE - if ( ( arg->co_op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) + if ( ( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) ) goto no_co_op_free; #endif #ifdef LDAP_SYNC - if ( ( arg->co_op->o_sync_mode & SLAP_SYNC_PERSIST ) ) + if ( ( op->o_sync_mode & SLAP_SYNC_PERSIST ) ) goto no_co_op_free; #endif co_op_free: - slap_op_free( arg->co_op ); + slap_op_free( op ); no_co_op_free: - arg->co_op = NULL; - arg->co_conn = NULL; - free( (char *) arg ); - arg = NULL; - switch( tag ) { case LBER_ERROR: case LDAP_REQ_UNBIND: @@ -1313,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; @@ -1440,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 ); @@ -1478,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", @@ -1490,10 +1493,14 @@ 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++; - connection_op_activate( conn, op ); + connection_op_activate( op ); } #ifdef NO_THREADS @@ -1504,7 +1511,7 @@ connection_input( #endif assert( conn->c_struct_state == SLAP_C_USED ); - return 0; + return rc; } static int @@ -1567,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 */ @@ -1581,7 +1591,7 @@ connection_resched( Connection *conn ) conn->c_n_ops_pending--; conn->c_n_ops_executing++; - connection_op_activate( conn, op ); + connection_op_activate( op ); if ( conn->c_conn_state == SLAP_C_BINDING ) { break; @@ -1590,46 +1600,44 @@ connection_resched( Connection *conn ) return 0; } -static int connection_op_activate( Connection *conn, Operation *op ) +static int connection_op_activate( Operation *op ) { - struct co_arg *arg; int status; ber_tag_t tag = op->o_tag; if(tag == LDAP_REQ_BIND) { - conn->c_conn_state = SLAP_C_BINDING; + op->o_conn->c_conn_state = SLAP_C_BINDING; } - arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) ); - arg->co_conn = conn; - arg->co_op = op; - - if (!arg->co_op->o_dn.bv_len) { - arg->co_op->o_authz = conn->c_authz; - arg->co_op->o_dn.bv_val = ch_strdup( conn->c_dn.bv_val ? - conn->c_dn.bv_val : "" ); - arg->co_op->o_ndn.bv_val = ch_strdup( conn->c_ndn.bv_val ? - conn->c_ndn.bv_val : "" ); + if (!op->o_dn.bv_len) { + op->o_authz = op->o_conn->c_authz; + ber_dupbv( &op->o_dn, &op->o_conn->c_dn ); + ber_dupbv( &op->o_ndn, &op->o_conn->c_ndn ); } - arg->co_op->o_authtype = conn->c_authtype; - ber_dupbv( &arg->co_op->o_authmech, &conn->c_authmech ); + op->o_authtype = op->o_conn->c_authtype; + ber_dupbv( &op->o_authmech, &op->o_conn->c_authmech ); - if (!arg->co_op->o_protocol) { - arg->co_op->o_protocol = conn->c_protocol - ? conn->c_protocol : LDAP_VERSION3; + if (!op->o_protocol) { + op->o_protocol = op->o_conn->c_protocol + ? op->o_conn->c_protocol : LDAP_VERSION3; } - arg->co_op->o_connid = conn->c_connid; + 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( &conn->c_ops, arg->co_op, o_next ); + LDAP_STAILQ_INSERT_TAIL( &op->o_conn->c_ops, op, o_next ); status = ldap_pvt_thread_pool_submit( &connection_pool, - connection_operation, (void *) arg ); + connection_operation, (void *) op ); if ( status != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( CONNECTION, ERR, "connection_op_activate: conn %lu thread pool submit failed.\n", - conn->c_connid, 0, 0 ); + op->o_connid, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "ldap_pvt_thread_pool_submit failed (%d)\n", status, 0, 0 ); diff --git a/servers/slapd/main.c b/servers/slapd/main.c index 51970015af..69fcd04c5a 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -360,6 +360,7 @@ int main( int argc, char **argv ) #endif extops_init(); + slap_op_init(); #ifdef SLAPD_MODULES if ( module_init() != 0 ) { @@ -574,6 +575,8 @@ destroy: module_kill(); #endif + slap_op_destroy(); + extops_kill(); stop: diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index 2a8da886da..499c884eae 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -18,6 +18,26 @@ #include "slapi.h" #endif +static ldap_pvt_thread_mutex_t slap_op_mutex; +static LDAP_STAILQ_HEAD(s_o, slap_op) slap_free_ops; + +void slap_op_init() +{ + ldap_pvt_thread_mutex_init( &slap_op_mutex ); + LDAP_STAILQ_INIT(&slap_free_ops); +} + +void slap_op_destroy() +{ + Operation *o; + + while ( (o = LDAP_STAILQ_FIRST( &slap_free_ops )) != NULL) { + LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next ); + LDAP_STAILQ_NEXT(o, o_next) = NULL; + ch_free( o ); + } + ldap_pvt_thread_mutex_destroy( &slap_op_mutex ); +} void slap_op_free( Operation *op ) @@ -62,7 +82,10 @@ slap_op_free( Operation *op ) } #endif /* defined( LDAP_SLAPI ) */ - free( (char *) op ); + memset( op, 0, sizeof(Operation) ); + ldap_pvt_thread_mutex_lock( &slap_op_mutex ); + LDAP_STAILQ_INSERT_HEAD( &slap_free_ops, op, o_next ); + ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); } Operation * @@ -75,7 +98,14 @@ slap_op_alloc( { Operation *op; - op = (Operation *) ch_calloc( 1, sizeof(Operation) ); + ldap_pvt_thread_mutex_lock( &slap_op_mutex ); + if (op = LDAP_STAILQ_FIRST( &slap_free_ops )) { + LDAP_STAILQ_REMOVE_HEAD( &slap_free_ops, o_next ); + } + ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); + + if (!op) + op = (Operation *) ch_calloc( 1, sizeof(Operation) ); op->o_ber = ber; op->o_msgid = msgid; diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index e2df5f9f6c..c9b34ecba0 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1086,6 +1086,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 aae80c7b3b..1bc94e0e16 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -79,6 +79,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 */