From: Kurt Zeilenga Date: Wed, 5 Apr 2006 00:34:42 +0000 (+0000) Subject: Changes suggested by Ando. X-Git-Tag: OPENLDAP_REL_ENG_2_3_21~31 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=2a8ed97b20685fb0b7fa372bbc548b1f20a38801;p=openldap Changes suggested by Ando. --- diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index 2c14022d2f..f6c25b2496 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -82,6 +82,7 @@ typedef struct ldapconn_t { #define LDAP_BACK_CONN_BINDING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_BINDING) unsigned lc_refcnt; + unsigned lc_binding; unsigned lc_flags; time_t lc_create_time; time_t lc_time; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index ed478507ef..36edfacd0e 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -105,11 +105,15 @@ ldap_back_bind( Operation *op, SlapReply *rs ) } done:; + assert( lc->lc_binding == 1 ); + lc->lc_binding = 0; + /* must re-insert if local DN changed as result of bind */ - if ( LDAP_BACK_CONN_ISBOUND( lc ) - && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) + if ( !LDAP_BACK_CONN_ISBOUND( lc ) + || ( LDAP_BACK_CONN_ISBOUND( lc ) + && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) ) { - int lerr; + int lerr = -1; /* wait for all other ops to release the connection */ retry_lock:; @@ -125,9 +129,12 @@ retry_lock:; ldap_back_conndn_cmp ); assert( lc != NULL ); - ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn ); - lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, - ldap_back_conndn_cmp, ldap_back_conndn_dup ); + if ( LDAP_BACK_CONN_ISBOUND( lc ) ) { + ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn ); + lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, + ldap_back_conndn_cmp, ldap_back_conndn_dup ); + } + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); if ( lerr == -1 ) { /* we can do this because lc_refcnt == 1 */ @@ -169,6 +176,35 @@ ldap_back_conndn_cmp( const void *c1, const void *c2 ) return rc; } +/* + * ldap_back_conndnlc_cmp + * + * compares two ldapconn_t based on the value of the conn pointer, + * the local DN and the lc pointer; used by avl stuff for insert, lookup + * and direct delete + */ +static int +ldap_back_conndnlc_cmp( const void *c1, const void *c2 ) +{ + const ldapconn_t *lc1 = (const ldapconn_t *)c1; + const ldapconn_t *lc2 = (const ldapconn_t *)c2; + int rc; + + /* If local DNs don't match, it is definitely not a match */ + /* For shared sessions, conn is NULL. Only explicitly + * bound sessions will have non-NULL conn. + */ + rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn ); + if ( rc == 0 ) { + rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn ); + if ( rc == 0 ) { + rc = SLAP_PTRCMP( lc1, lc2 ); + } + } + + return rc; +} + /* * ldap_back_conn_cmp * @@ -227,9 +263,9 @@ ravl_print( Avlnode *root, int depth ) } lc = root->avl_data; - fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s\n", + fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n", (void *)lc, lc->lc_local_ndn.bv_val, (void *)lc->lc_conn, - avl_bf2str( root->avl_bf) ); + avl_bf2str( root->avl_bf ), lc->lc_refcnt ); ravl_print( root->avl_left, depth+1 ); } @@ -445,10 +481,9 @@ ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_bac } ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers ); - /* automatically chase referrals ("[dont-]chase-referrals" statement) */ - if ( LDAP_BACK_CHASE_REFERRALS( li ) ) { - ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); - } + /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ + ldap_set_option( ld, LDAP_OPT_REFERRALS, + LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); #ifdef HAVE_TLS rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls, @@ -465,6 +500,7 @@ ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_bac } (*lcp)->lc_ld = ld; (*lcp)->lc_refcnt = 1; + (*lcp)->lc_binding = 1; #ifdef HAVE_TLS if ( is_tls ) { LDAP_BACK_CONN_ISTLS_SET( *lcp ); @@ -499,7 +535,7 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok ) ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; ldapconn_t *lc = NULL, lc_curr = { 0 }; - int refcnt = 1; + int refcnt = 1, binding = 1; /* Internal searches are privileged and shared. So is root. */ if ( op->o_do_not_cache || be_isroot( op ) ) { @@ -534,6 +570,7 @@ retry_lock: goto retry_lock; } refcnt = ++lc->lc_refcnt; + binding = ++lc->lc_binding; } ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } @@ -584,6 +621,7 @@ retry_lock: (caddr_t)&lc_curr, ldap_back_conndn_cmp ); if ( tmplc != NULL ) { refcnt = ++tmplc->lc_refcnt; + binding = ++tmplc->lc_binding; ldap_back_conn_free( lc ); lc = tmplc; } @@ -601,6 +639,7 @@ retry_lock: ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); assert( lc->lc_refcnt == 1 ); + assert( lc->lc_binding == 1 ); rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conndn_cmp, ldap_back_conndn_dup ); @@ -611,8 +650,8 @@ retry_lock: ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); Debug( LDAP_DEBUG_TRACE, - "=>ldap_back_getconn: conn %p inserted (refcnt=%u)\n", - (void *)lc, refcnt, 0 ); + "=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n", + (void *)lc, refcnt, binding ); /* Err could be -1 in case a duplicate ldapconn is inserted */ if ( rs->sr_err != 0 ) { @@ -626,20 +665,30 @@ retry_lock: } } else { + char buf[ SLAP_TEXT_BUFLEN ]; + int expiring = 0; + if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout ) || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) ) { - /* in case of failure, it frees/taints lc and sets it to NULL */ - if ( !ldap_back_retry( &lc, op, rs, sendok ) ) { - lc = NULL; - } + expiring = 1; + + /* let it be used, but taint/delete it so that + * no-one else can look it up any further */ + ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); + (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, + ldap_back_conndnlc_cmp ); + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } - if ( lc ) { + if ( LogTest( LDAP_DEBUG_TRACE ) ) { + snprintf( buf, sizeof( buf ), + "conn %p fetched refcnt=%u binding=%u%s", + (void *)lc, refcnt, binding, expiring ? " expiring" : "" ); Debug( LDAP_DEBUG_TRACE, - "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n", - (void *)lc, refcnt, 0 ); + "=>ldap_back_getconn: %s.\n", buf, 0, 0 ); } + } if ( li->li_idle_timeout && lc ) { @@ -690,15 +739,57 @@ ldap_back_dobind_int( { ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private; - int rc = LDAP_BACK_CONN_ISBOUND( lc ); + int rc, binding = 0; ber_int_t msgid; assert( retries >= 0 ); - if ( rc ) { - return rc; +retry_lock:; + if ( dolock ) { + ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex ); + } + + if ( binding == 0 ) { + /* check if already bound */ + rc = LDAP_BACK_CONN_ISBOUND( lc ); + if ( rc ) { + lc->lc_binding--; + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); + } + return rc; + } + + if ( LDAP_BACK_CONN_BINDING( lc ) ) { + /* if someone else is about to bind it, give up and retry */ + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); + } + ldap_pvt_thread_yield(); + goto retry_lock; + + } else { + /* otherwise this thread will bind it */ + LDAP_BACK_CONN_BINDING_SET( lc ); + binding = 1; + } } + /* wait for pending operations to finish */ + /* FIXME: may become a bottleneck! */ + if ( lc->lc_refcnt != lc->lc_binding ) { + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); + } + ldap_pvt_thread_yield(); + goto retry_lock; + } + + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); + } + +#if 0 while ( lc->lc_refcnt > 1 ) { ldap_pvt_thread_yield(); rc = LDAP_BACK_CONN_ISBOUND( lc ); @@ -714,6 +805,7 @@ ldap_back_dobind_int( if ( dolock ) { ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); } +#endif /* * FIXME: we need to let clients use proxyAuthz @@ -822,6 +914,7 @@ retry:; } } + lc->lc_binding--; ldap_back_freeconn( op, lc, dolock ); rs->sr_err = slap_map_api2result( rs ); @@ -834,6 +927,7 @@ retry:; } done:; + lc->lc_binding--; LDAP_BACK_CONN_BINDING_CLEAR( lc ); rc = LDAP_BACK_CONN_ISBOUND( lc ); if ( !rc ) { @@ -1036,6 +1130,20 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_ *lcp = NULL; } } + + } else { + Debug( LDAP_DEBUG_TRACE, + "ldap_back_retry: conn %p refcnt=%u unable to retry.\n", + (void *)(*lcp), (*lcp)->lc_refcnt, 0 ); + + ldap_back_release_conn_lock( op, rs, *lcp, 0 ); + *lcp = NULL; + + if ( sendok ) { + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "unable to retry"; + send_ldap_result( op, rs ); + } } ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex ); @@ -1388,9 +1496,9 @@ ldap_back_proxy_authz_ctrl( { /* ndn is not authorized * to use idassert */ - return rc; + rs->sr_err = rc; } - return rs->sr_err; + goto done; } } diff --git a/servers/slapd/back-ldap/chain.c b/servers/slapd/back-ldap/chain.c index 5b7816584e..779be7697b 100644 --- a/servers/slapd/back-ldap/chain.c +++ b/servers/slapd/back-ldap/chain.c @@ -219,25 +219,6 @@ ldap_chain_uri_dup( void *c1, void *c2 ) return 0; } -static int -ldap_chain_operational( Operation *op, SlapReply *rs ) -{ - /* Trap entries generated by back-ldap. - * - * FIXME: we need a better way to recognize them; a cleaner - * solution would be to be able to intercept the response - * of be_operational(), so that we can divert only those - * calls that fail because operational attributes were - * requested for entries that do not belong to the underlying - * database. This fix is likely to intercept also entries - * generated by back-perl and so. */ - if ( rs->sr_entry->e_private == NULL ) { - return 0; - } - - return SLAP_CB_CONTINUE; -} - /* * Search specific response that strips entryDN from entries */ @@ -269,6 +250,10 @@ ldap_chain_cb_search_response( Operation *op, SlapReply *rs ) break; } } + + /* tell the frontend not to add generated + * operational attributes */ + rs->sr_flags |= REP_NO_OPERATIONALS; return SLAP_CB_CONTINUE; @@ -355,7 +340,7 @@ static int ldap_chain_op( Operation *op, SlapReply *rs, - int ( *op_f )( Operation *op, SlapReply *rs ), + BI_op_func *op_f, BerVarray ref ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; @@ -461,7 +446,7 @@ Document: draft-ietf-ldapbis-protocol-27.txt } } - rc = ( *op_f )( op, rs ); + rc = op_f( op, rs ); cleanup:; ldap_memfree( li.li_uri ); @@ -766,7 +751,7 @@ cleanup:; /* FIXME: ldap_back_extended() by design * doesn't send result; frontend is expected * to send it... */ - /* FIXME: what aboit chaining? */ + /* FIXME: what about chaining? */ if ( rc != SLAPD_ABANDON ) { send_ldap_extended( op, rs ); rc = LDAP_SUCCESS; @@ -786,7 +771,13 @@ cleanup:; case LDAP_SUCCESS: case LDAP_REFERRAL: /* slapd-ldap sent response */ - assert( sc2.sc_private == LDAP_CH_RES ); + if ( !op->o_abandon && sc2.sc_private != LDAP_CH_RES ) { + /* FIXME: should we send response? */ + Debug( LDAP_DEBUG_ANY, + "%s: ldap_chain_response: " + "overlay should have sent result.\n", + op->o_log_prefix, 0, 0 ); + } break; default: @@ -1807,17 +1798,6 @@ chain_init( void ) ldapchain.on_bi.bi_db_close = ldap_chain_db_close; ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy; - /* ... otherwise the underlying backend's function would be called, - * likely passing an invalid entry; on the contrary, the requested - * operational attributes should have been returned while chasing - * the referrals. This all in all is a bit messy, because part - * of the operational attributes are generated by the backend; - * part by the frontend; back-ldap should receive all the available - * ones from the remote server, but then, on its own, it strips those - * it assumes will be (re)generated by the frontend (e.g. - * subschemaSubentry.) */ - ldapchain.on_bi.bi_operational = ldap_chain_operational; - ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy; ldapchain.on_response = ldap_chain_response; diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 6dd8363a19..a00d820b64 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -314,6 +314,10 @@ ldap_back_cf_gen( ConfigArgs *c ) struct berval bv = BER_BVNULL; rc = 0; + if ( li == NULL ) { + return 1; + } + switch( c->type ) { case LDAP_BACK_CFG_URI: if ( li->li_uri != NULL ) { diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 2be811f1fa..e76e2cdf32 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -303,6 +303,7 @@ retry: rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_flags = 0; + rs->sr_err = LDAP_SUCCESS; rc = rs->sr_err = send_search_entry( op, rs ); if ( !BER_BVISNULL( &ent.e_name ) ) { assert( ent.e_name.bv_val != bdn.bv_val ); diff --git a/servers/slapd/back-meta/add.c b/servers/slapd/back-meta/add.c index 89453b8ec8..03187a90e6 100644 --- a/servers/slapd/back-meta/add.c +++ b/servers/slapd/back-meta/add.c @@ -169,9 +169,10 @@ retry:; attrs, op->o_ctrls, NULL, &msgid ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) { + if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { goto retry; } + goto cleanup; } else if ( rs->sr_err == LDAP_SUCCESS ) { struct timeval tv, *tvp = NULL; @@ -228,7 +229,9 @@ cleanup:; } done:; - meta_back_release_conn( op, mc ); + if ( mc ) { + meta_back_release_conn( op, mc ); + } return rs->sr_err; } diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 2cf8369c7c..9d6eba8ab8 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -167,24 +167,16 @@ typedef struct metasingleconn_t { /* NOTE: lc_lcflags is redefined to msc_mscflags to reuse the macros * defined for back-ldap */ #define lc_lcflags msc_mscflags -#if 0 - int msc_bound; -#define META_UNBOUND 0 -#define META_BOUND 1 -#define META_ANONYMOUS 2 -#endif - - time_t msc_create_time; - time_t msc_time; struct metainfo_t *msc_info; } metasingleconn_t; typedef struct metaconn_t { struct slap_conn *mc_conn; - ldap_pvt_thread_mutex_t mc_mutex; unsigned mc_refcnt; - int mc_tainted; + + time_t mc_create_time; + time_t mc_time; struct berval mc_local_ndn; /* NOTE: msc_mscflags is used to recycle the #define @@ -230,8 +222,6 @@ typedef struct metatarget_t { unsigned mt_flags; int mt_version; time_t mt_network_timeout; - time_t mt_conn_ttl; - time_t mt_idle_timeout; struct timeval mt_bind_timeout; #define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT time_t mt_timeout[ LDAP_BACK_OP_LAST ]; @@ -300,20 +290,20 @@ meta_back_getconn( ldap_back_send_t sendok ); extern void -meta_back_release_conn( +meta_back_release_conn_lock( Operation *op, - metaconn_t *mc ); + metaconn_t *mc, + int dofree, + int dolock ); +#define meta_back_release_conn(op, mc) meta_back_release_conn_lock( (op), (mc), 0, 1 ) extern int -meta_back_retry_lock( +meta_back_retry( Operation *op, SlapReply *rs, - metaconn_t *mc, + metaconn_t **mcp, int candidate, - ldap_back_send_t sendok, - int dolock ); -#define meta_back_retry(op, rs, mc, candidate, sendok) \ - meta_back_retry_lock((op), (rs), (mc), (candidate), (sendok), 1) + ldap_back_send_t sendok ); extern void meta_back_conn_free( @@ -348,7 +338,7 @@ extern int meta_back_single_dobind( Operation *op, SlapReply *rs, - metaconn_t *msc, + metaconn_t **mcp, int candidate, ldap_back_send_t sendok, int retries, @@ -372,12 +362,12 @@ meta_back_conn_cmp( const void *c2 ); extern int -meta_back_dnconn_cmp( +meta_back_conndn_cmp( const void *c1, const void *c2 ); extern int -meta_back_dnconn_dup( +meta_back_conndn_dup( void *c1, void *c2 ); @@ -406,6 +396,11 @@ extern int meta_clear_one_candidate( metasingleconn_t *mc ); +extern int +meta_clear_candidates( + Operation *op, + metaconn_t *mc ); + /* * Dn cache stuff (experimental) */ diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index 9f5c0962da..43f8297378 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -179,6 +179,10 @@ meta_back_bind( Operation *op, SlapReply *rs ) if ( lerr != LDAP_SUCCESS ) { rc = rs->sr_err = lerr; + /* FIXME: in some cases (e.g. unavailable) + * do not assume it's not candidate; rather + * mark this as an error to be eventually + * reported to client */ candidates[ i ].sr_tag = META_NOT_CANDIDATE; break; } @@ -192,6 +196,7 @@ meta_back_bind( Operation *op, SlapReply *rs ) } if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) { + metaconn_t *tmpmc; int lerr; /* wait for all other ops to release the connection */ @@ -204,20 +209,16 @@ retry_lock:; } assert( mc->mc_refcnt == 1 ); - mc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, - meta_back_dnconn_cmp ); - assert( mc != NULL ); + tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, + meta_back_conndn_cmp ); + assert( tmpmc == mc ); ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, - meta_back_dnconn_cmp, meta_back_dnconn_dup ); + meta_back_conndn_cmp, meta_back_conndn_dup ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( lerr == -1 ) { - for ( i = 0; i < mi->mi_ntargets; ++i ) { - if ( mc->mc_conns[ i ].msc_ld != NULL ) { - meta_clear_one_candidate( &mc->mc_conns[ i ] ); - } - } + meta_clear_candidates( op, mc ); /* we can do this because mc_refcnt == 1 */ mc->mc_refcnt = 0; @@ -304,8 +305,9 @@ meta_back_single_bind( dc.ctx = "bindDN"; if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - send_ldap_result( op, rs ); - return -1; + rs->sr_text = "DN rewrite error"; + rs->sr_err = LDAP_OTHER; + return rs->sr_err; } } else { @@ -375,15 +377,15 @@ retry:; } snprintf( buf, sizeof( buf ), - "err=%d nretries=%d", - rs->sr_err, nretries ); + "err=%d (%s) nretries=%d", + rs->sr_err, ldap_err2string( rs->sr_err ), nretries ); Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_bind[%d]: %s.\n", op->o_log_prefix, candidate, buf ); rc = slap_map_api2result( rs ); if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) { - rc = meta_back_retry( op, rs, mc, candidate, LDAP_BACK_DONTSEND ); + rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ); if ( rc ) { if ( nretries > 0 ) { nretries--; @@ -391,6 +393,7 @@ retry:; ldap_pvt_thread_yield(); goto rebind; } + goto return_results; } break; @@ -440,7 +443,7 @@ int meta_back_single_dobind( Operation *op, SlapReply *rs, - metaconn_t *mc, + metaconn_t **mcp, int candidate, ldap_back_send_t sendok, int nretries, @@ -448,6 +451,7 @@ meta_back_single_dobind( { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = &mi->mi_targets[ candidate ]; + metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; int rc; static struct berval cred = BER_BVC( "" ); @@ -457,6 +461,24 @@ meta_back_single_dobind( assert( !LDAP_BACK_CONN_ISBOUND( msc ) ); + /* + * meta_back_single_dobind() calls meta_back_single_bind() + * if required. + */ + if ( be_isroot( op ) && !BER_BVISNULL( &mi->mi_targets[ candidate ].mt_pseudorootdn ) ) + { + Operation op2 = *op; + + op2.o_tag = LDAP_REQ_BIND; + op2.o_req_dn = mi->mi_targets[ candidate ].mt_pseudorootdn; + op2.o_req_ndn = mi->mi_targets[ candidate ].mt_pseudorootdn; + op2.orb_cred = mi->mi_targets[ candidate ].mt_pseudorootpw; + op2.orb_method = LDAP_AUTH_SIMPLE; + + rc = meta_back_single_bind( &op2, rs, *mcp, candidate, 0 ); + goto done; + } + /* * Otherwise an anonymous bind is performed * (note: if the target was already bound, the anonymous @@ -531,17 +553,14 @@ retry:; } snprintf( buf, sizeof( buf ), - "err=%d nretries=%d", - rs->sr_err, nretries ); + "err=%d (%s) nretries=%d", + rs->sr_err, ldap_err2string( rs->sr_err ), nretries ); Debug( LDAP_DEBUG_ANY, "### %s meta_back_single_dobind[%d]: %s.\n", op->o_log_prefix, candidate, buf ); rc = slap_map_api2result( rs ); if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) { - /* NOTE: we do not use meta_back_retry() here - * to avoid circular loops; mc_mutex is set - * by the caller */ if ( dolock ) { ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); } @@ -558,6 +577,7 @@ retry:; mt, mc, candidate, LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND ); + LDAP_BACK_CONN_BINDING_SET( msc ); } else { /* can't do anything about it */ @@ -592,9 +612,16 @@ retry:; rc = slap_map_api2result( rs ); } +done:; rs->sr_err = rc; - if ( rc != LDAP_SUCCESS && ( sendok & LDAP_BACK_SENDERR ) ) { - send_ldap_result( op, rs ); + if ( rc != LDAP_SUCCESS && META_BACK_ONERR_STOP( mi ) ) { + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + meta_back_release_conn_lock( op, mc, 1, dolock ); + *mcp = NULL; + + if ( sendok & LDAP_BACK_SENDERR ) { + send_ldap_result( op, rs ); + } } return rc; @@ -628,8 +655,6 @@ meta_back_dobind( LDAP_BACK_PCONN_ID( mc->mc_conn ), isroot ? " (isroot)" : "" ); - ldap_pvt_thread_mutex_lock( &mc->mc_mutex ); - /* * all the targets are bound as pseudoroot */ @@ -656,44 +681,61 @@ meta_back_dobind( /* * If the target is already bound it is skipped */ + +retry_binding:; + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ++bound; continue; - } -retry:; - if ( isroot && !BER_BVISNULL( &mi->mi_targets[ i ].mt_pseudorootdn ) ) - { - Operation op2 = *op; - - op2.o_tag = LDAP_REQ_BIND; - op2.o_req_dn = mi->mi_targets[ i ].mt_pseudorootdn; - op2.o_req_ndn = mi->mi_targets[ i ].mt_pseudorootdn; - op2.orb_cred = mi->mi_targets[ i ].mt_pseudorootpw; - op2.orb_method = LDAP_AUTH_SIMPLE; - - rootdn = mi->mi_targets[ i ].mt_pseudorootdn.bv_val; - - rc = meta_back_single_bind( &op2, rs, mc, i, 0 ); + } else if ( LDAP_BACK_CONN_BINDING( msc ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + ldap_pvt_thread_yield(); + goto retry_binding; } else { - rc = meta_back_single_dobind( op, rs, mc, i, - LDAP_BACK_DONTSEND, mt->mt_nretries, 1 ); - } + LDAP_BACK_CONN_BINDING_SET( msc ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } +retry:; + rc = meta_back_single_dobind( op, rs, &mc, i, + LDAP_BACK_DONTSEND, mt->mt_nretries, 1 ); + /* + * NOTE: meta_back_single_dobind() already retries; + * in case of failure, it resets mc... + */ if ( rc != LDAP_SUCCESS ) { char buf[ SLAP_TEXT_BUFLEN ]; + if ( mc == NULL ) { + /* meta_back_single_dobind() already sent + * response and released connection */ + goto send_err; + } + + if ( rc == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( meta_back_retry_lock( op, rs, mc, i, LDAP_BACK_DONTSEND, 0 ) ) { + if ( meta_back_retry( op, rs, &mc, i, sendok ) ) { goto retry; } + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + + return 0; } + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + snprintf( buf, sizeof( buf ), - "meta_back_dobind[%d]: (%s) err=%d.", - i, rootdn ? rootdn : "anonymous", rc ); + "meta_back_dobind[%d]: (%s) err=%d (%s).", + i, rootdn ? rootdn : "anonymous", + rc, ldap_err2string( rc ) ); Debug( LDAP_DEBUG_ANY, "%s %s\n", op->o_log_prefix, buf, 0 ); @@ -711,6 +753,7 @@ retry:; bound = 0; goto done; } + continue; } /* else */ @@ -720,17 +763,18 @@ retry:; op->o_log_prefix, i, rootdn ? rootdn : "anonymous" ); + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( rootdn ) { LDAP_BACK_CONN_ISBOUND_SET( msc ); } else { LDAP_BACK_CONN_ISANON_SET( msc ); } + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ++bound; } done:; - ldap_pvt_thread_mutex_unlock( &mc->mc_mutex ); - Debug( LDAP_DEBUG_TRACE, "%s meta_back_dobind: conn=%ld bound=%d\n", op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound ); @@ -738,15 +782,18 @@ done:; if ( bound == 0 ) { meta_back_release_conn( op, mc ); +send_err:; if ( sendok & LDAP_BACK_SENDERR ) { if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = LDAP_BUSY; } send_ldap_result( op, rs ); } + + return 0; } - return( bound > 0 ); + return ( bound > 0 ); } /* diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index 1986ab3bd6..794d1b3a47 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -206,3 +206,22 @@ meta_clear_one_candidate( return 0; } +/* + * meta_clear_candidates + * + * clears all candidates + */ +int +meta_clear_candidates( Operation *op, metaconn_t *mc ) +{ + metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; + int c; + + for ( c = 0; c < mi->mi_ntargets; c++ ) { + if ( mc->mc_conns[ c ].msc_ld != NULL ) { + meta_clear_one_candidate( &mc->mc_conns[ c ] ); + } + } + + return 0; +} diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index cf26945dfe..4e5997a64c 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -158,8 +158,6 @@ meta_back_db_config( mi->mi_targets[ i ].mt_flags = mi->mi_flags; mi->mi_targets[ i ].mt_version = mi->mi_version; mi->mi_targets[ i ].mt_network_timeout = mi->mi_network_timeout; - mi->mi_targets[ i ].mt_conn_ttl = mi->mi_conn_ttl; - mi->mi_targets[ i ].mt_idle_timeout = mi->mi_idle_timeout; mi->mi_targets[ i ].mt_bind_timeout = mi->mi_bind_timeout; for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) { mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ]; @@ -448,9 +446,6 @@ meta_back_db_config( /* idle timeout when connecting to ldap servers */ } else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) { unsigned long t; - time_t *tp = mi->mi_ntargets ? - &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_idle_timeout - : &mi->mi_idle_timeout; switch ( argc ) { case 1: @@ -475,14 +470,11 @@ meta_back_db_config( } - *tp = (time_t)t; + mi->mi_idle_timeout = (time_t)t; /* conn ttl */ } else if ( strcasecmp( argv[ 0 ], "conn-ttl" ) == 0 ) { unsigned long t; - time_t *tp = mi->mi_ntargets ? - &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_conn_ttl - : &mi->mi_conn_ttl; switch ( argc ) { case 1: @@ -507,7 +499,7 @@ meta_back_db_config( } - *tp = (time_t)t; + mi->mi_conn_ttl = (time_t)t; /* bind timeout when connecting to ldap servers */ } else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) { diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 7af76de199..657881ca50 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -40,13 +40,13 @@ #define PRINT_CONNTREE 0 /* - * meta_back_dnconn_cmp + * meta_back_conndn_cmp * * compares two struct metaconn based on the value of the conn pointer * and of the local DN; used by avl stuff */ int -meta_back_dnconn_cmp( +meta_back_conndn_cmp( const void *c1, const void *c2 ) { @@ -66,6 +66,36 @@ meta_back_dnconn_cmp( return rc; } +/* + * meta_back_conndnmc_cmp + * + * compares two struct metaconn based on the value of the conn pointer, + * the local DN and the struct pointer; used by avl stuff + */ +static int +meta_back_conndnmc_cmp( + const void *c1, + const void *c2 ) +{ + metaconn_t *mc1 = ( metaconn_t * )c1; + metaconn_t *mc2 = ( metaconn_t * )c2; + int rc; + + /* If local DNs don't match, it is definitely not a match */ + /* For shared sessions, conn is NULL. Only explicitly + * bound sessions will have non-NULL conn. + */ + rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn ); + if ( rc == 0 ) { + rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn ); + if ( rc == 0 ) { + rc = SLAP_PTRCMP( mc1, mc2 ); + } + } + + return rc; +} + /* * meta_back_conn_cmp * @@ -87,13 +117,13 @@ meta_back_conn_cmp( } /* - * meta_back_dnconn_dup + * meta_back_conndn_dup * * returns -1 in case a duplicate struct metaconn has been inserted; * used by avl stuff */ int -meta_back_dnconn_dup( +meta_back_conndn_dup( void *c1, void *c2 ) { @@ -183,16 +213,14 @@ metaconn_alloc( mc->mc_conns[ i ].msc_ld = NULL; BER_BVZERO( &mc->mc_conns[ i ].msc_bound_ndn ); BER_BVZERO( &mc->mc_conns[ i ].msc_cred ); - LDAP_BACK_CONN_ISBOUND_CLEAR( &mc->mc_conns[ i ] ); + mc->mc_conns[ i ].msc_mscflags = 0; mc->mc_conns[ i ].msc_info = mi; } BER_BVZERO( &mc->mc_local_ndn ); mc->msc_mscflags = 0; mc->mc_authz_target = META_BOUND_NONE; - ldap_pvt_thread_mutex_init( &mc->mc_mutex ); mc->mc_refcnt = 1; - mc->mc_tainted = 0; return mc; } @@ -240,29 +268,10 @@ meta_back_init_one_conn( * Already init'ed */ if ( msc->msc_ld != NULL ) { - int doreturn = 1; - - if ( ( mt->mt_idle_timeout != 0 && op->o_time > msc->msc_time + mt->mt_idle_timeout ) - || ( mt->mt_conn_ttl != 0 && op->o_time > msc->msc_create_time + mt->mt_conn_ttl ) ) - { - Debug( LDAP_DEBUG_TRACE, - "%s meta_back_init_one_conn[%d]: idle timeout/ttl.\n", - op->o_log_prefix, candidate, 0 ); - if ( meta_back_retry( op, rs, mc, candidate, sendok ) ) { - return rs->sr_err; - } - - doreturn = 0; - } - - if ( mt->mt_idle_timeout != 0 ) { - msc->msc_time = op->o_time; - } - - if ( doreturn ) { - return rs->sr_err = LDAP_SUCCESS; - } + return rs->sr_err = LDAP_SUCCESS; } + + msc->msc_mscflags = 0; /* * Attempts to initialize the connection to the target ds @@ -279,10 +288,9 @@ meta_back_init_one_conn( vers = op->o_conn->c_protocol; ldap_set_option( msc->msc_ld, LDAP_OPT_PROTOCOL_VERSION, &vers ); - /* automatically chase referrals ("chase-referrals"/"dont-chase-referrals" statement) */ - if ( LDAP_BACK_CHASE_REFERRALS( mi ) ) { - ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON ); - } + /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */ + ldap_set_option( msc->msc_ld, LDAP_OPT_REFERRALS, + LDAP_BACK_CHASE_REFERRALS( mi ) ? LDAP_OPT_ON : LDAP_OPT_OFF ); #ifdef HAVE_TLS /* start TLS ("tls [try-]{start|propagate}" statement) */ @@ -447,8 +455,6 @@ retry:; assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); - LDAP_BACK_CONN_ISBOUND_CLEAR( msc ); - error_return:; if ( rs->sr_err == LDAP_SUCCESS ) { /* @@ -456,14 +462,6 @@ error_return:; */ ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn ); - if ( mt->mt_idle_timeout ) { - msc->msc_time = op->o_time; - } - - if ( mt->mt_conn_ttl ) { - msc->msc_create_time = op->o_time; - } - } else { rs->sr_err = slap_map_api2result( rs ); if ( sendok & LDAP_BACK_SENDERR ) { @@ -476,38 +474,31 @@ error_return:; } /* - * meta_back_retry_lock + * meta_back_retry * * Retries one connection */ int -meta_back_retry_lock( +meta_back_retry( Operation *op, SlapReply *rs, - metaconn_t *mc, + metaconn_t **mcp, int candidate, - ldap_back_send_t sendok, - int dolock ) + ldap_back_send_t sendok ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = &mi->mi_targets[ candidate ]; - int rc = LDAP_UNAVAILABLE; + metaconn_t *mc = *mcp; metasingleconn_t *msc = &mc->mc_conns[ candidate ]; + int rc = LDAP_UNAVAILABLE, + binding = LDAP_BACK_CONN_BINDING( msc ); -retry_lock:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); assert( mc->mc_refcnt > 0 ); - if ( mc->mc_refcnt == 1 ) { char buf[ SLAP_TEXT_BUFLEN ]; - while ( dolock && ldap_pvt_thread_mutex_trylock( &mc->mc_mutex ) ) { - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - ldap_pvt_thread_yield(); - goto retry_lock; - } - snprintf( buf, sizeof( buf ), "retrying URI=\"%s\" DN=\"%s\"", mt->mt_uri, @@ -525,33 +516,30 @@ retry_lock:; /* mc here must be the regular mc, reset and ready for init */ rc = meta_back_init_one_conn( op, rs, mt, mc, candidate, LDAP_BACK_CONN_ISPRIV( mc ), sendok ); + if ( binding ) { + LDAP_BACK_CONN_BINDING_SET( msc ); + } if ( rc == LDAP_SUCCESS ) { - if ( be_isroot( op ) && !BER_BVISNULL( &mi->mi_targets[ candidate ].mt_pseudorootdn ) ) - { - Operation op2 = *op; - - op2.o_tag = LDAP_REQ_BIND; - op2.o_req_dn = mi->mi_targets[ candidate ].mt_pseudorootdn; - op2.o_req_ndn = mi->mi_targets[ candidate ].mt_pseudorootdn; - op2.orb_cred = mi->mi_targets[ candidate ].mt_pseudorootpw; - op2.orb_method = LDAP_AUTH_SIMPLE; - - rc = meta_back_single_bind( &op2, rs, mc, candidate, 0 ); - - } else { - rc = meta_back_single_dobind( op, rs, mc, candidate, - sendok, mt->mt_nretries, 0 ); - } + rc = meta_back_single_dobind( op, rs, mcp, candidate, + sendok, mt->mt_nretries, 0 ); } - - if ( dolock ) { - ldap_pvt_thread_mutex_unlock( &mc->mc_mutex ); - } } if ( rc != LDAP_SUCCESS ) { - mc->mc_tainted = 1; + if ( *mcp != NULL ) { + if ( binding ) { + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + } + meta_back_release_conn_lock( op, mc, 1, 0 ); + *mcp = NULL; + } + + if ( sendok ) { + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = NULL; + send_ldap_result( op, rs ); + } } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); @@ -779,8 +767,11 @@ meta_back_getconn( meta_op_type op_type = META_OP_REQUIRE_SINGLE; - int parent = 0, - newparent = 0; + enum { + META_DNTYPE_ENTRY, + META_DNTYPE_PARENT, + META_DNTYPE_NEWPARENT + } dn_type = META_DNTYPE_ENTRY; struct berval ndn = op->o_req_ndn, pndn; @@ -811,21 +802,26 @@ meta_back_getconn( retry_lock: ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, - (caddr_t)&mc_curr, meta_back_dnconn_cmp ); + (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc ) { - if ( mc->mc_tainted ) { - rs->sr_err = LDAP_UNAVAILABLE; - rs->sr_text = "remote server unavailable"; - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - return NULL; + if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) + || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) ) + { + /* don't let anyone else use this expired connection */ + (void)avl_delete( &mi->mi_conninfo.lai_tree, + (caddr_t)mc, meta_back_conndnmc_cmp ); + + Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n", + op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) ); } - + /* Don't reuse connections while they're still binding */ if ( LDAP_BACK_CONN_BINDING( mc ) ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_lock; } + mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); @@ -835,7 +831,7 @@ retry_lock: case LDAP_REQ_ADD: /* if we go to selection, the entry must not exist, * and we must be able to resolve the parent */ - parent = 1; + dn_type = META_DNTYPE_PARENT; dnParent( &ndn, &pndn ); break; @@ -843,7 +839,7 @@ retry_lock: /* if nnewSuperior is not NULL, it must resolve * to the same candidate as the req_ndn */ if ( op->orr_nnewSup ) { - newparent = 1; + dn_type = META_DNTYPE_NEWPARENT; } break; @@ -964,7 +960,7 @@ retry_lock: if ( i == META_TARGET_NONE ) { i = meta_back_get_candidate( op, rs, &ndn ); - if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) { + if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) { i = meta_back_get_candidate( op, rs, &pndn ); } @@ -986,7 +982,7 @@ retry_lock: } } - if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) + if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i ) { if ( mc != NULL ) { meta_back_release_conn( op, mc ); @@ -1011,10 +1007,18 @@ retry_lock: * the reason is that the connection might have been * created by meta_back_get_candidate() */ if ( !( sendok & LDAP_BACK_BINDING ) ) { +retry_lock2:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, - (caddr_t)&mc_curr, meta_back_dnconn_cmp ); + (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc != NULL ) { + /* Don't reuse connections while they're still binding */ + if ( LDAP_BACK_CONN_BINDING( mc ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + ldap_pvt_thread_yield(); + goto retry_lock2; + } + mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); @@ -1173,14 +1177,23 @@ done:; rs->sr_err = LDAP_SUCCESS; rs->sr_text = NULL; + /* touch the timestamp */ + if ( mi->mi_idle_timeout != 0 ) { + mc->mc_time = op->o_time; + } + if ( new_conn ) { + if ( mi->mi_conn_ttl ) { + mc->mc_create_time = op->o_time; + } + /* * Inserts the newly created metaconn in the avl tree */ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, - meta_back_dnconn_cmp, meta_back_dnconn_dup ); + meta_back_conndn_cmp, meta_back_conndn_dup ); #if PRINT_CONNTREE > 0 myprint( mi->mi_conninfo.lai_tree ); @@ -1226,22 +1239,36 @@ done:; } void -meta_back_release_conn( +meta_back_release_conn_lock( Operation *op, - metaconn_t *mc ) + metaconn_t *mc, + int dofree, + int dolock ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; assert( mc != NULL ); - ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + if ( dolock ) { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + } assert( mc->mc_refcnt > 0 ); mc->mc_refcnt--; LDAP_BACK_CONN_BINDING_CLEAR( mc ); - if ( mc->mc_refcnt == 0 && mc->mc_tainted ) { - (void)avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, - meta_back_dnconn_cmp ); - meta_back_conn_free( mc ); + if ( dofree + || ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) + || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) ) + { + Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld expired.\n", + op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) ); + (void)avl_delete( &mi->mi_conninfo.lai_tree, + ( caddr_t )mc, meta_back_conndnmc_cmp ); + if ( mc->mc_refcnt == 0 ) { + meta_clear_candidates( op, mc ); + meta_back_conn_free( mc ); + } + } + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } diff --git a/servers/slapd/back-meta/delete.c b/servers/slapd/back-meta/delete.c index f0f5e4259f..d904efb903 100644 --- a/servers/slapd/back-meta/delete.c +++ b/servers/slapd/back-meta/delete.c @@ -67,9 +67,10 @@ retry:; mdn.bv_val, op->o_ctrls, NULL, &msgid ); if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { do_retry = 0; - if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) { + if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { goto retry; } + goto cleanup; } else if ( rs->sr_err == LDAP_SUCCESS ) { struct timeval tv, *tvp = NULL; @@ -122,7 +123,9 @@ cleanup:; } done:; - meta_back_release_conn( op, mc ); + if ( mc ) { + meta_back_release_conn( op, mc ); + } return rs->sr_err; } diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 6ce7831391..b6944c8b4d 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -150,7 +150,6 @@ meta_back_conn_free( (void)meta_clear_one_candidate( &mc->mc_conns[ i ] ); } - ldap_pvt_thread_mutex_destroy( &mc->mc_mutex ); free( mc ); } diff --git a/servers/slapd/back-monitor/cache.c b/servers/slapd/back-monitor/cache.c index 071ae06ab9..89bfe044b4 100644 --- a/servers/slapd/back-monitor/cache.c +++ b/servers/slapd/back-monitor/cache.c @@ -89,7 +89,6 @@ monitor_cache_add( assert( e != NULL ); mp = ( monitor_entry_t *)e->e_private; - ldap_pvt_thread_mutex_init( &mp->mp_mutex ); mc = ( monitor_cache_t * )ch_malloc( sizeof( monitor_cache_t ) ); mc->mc_ndn = e->e_nname; diff --git a/servers/slapd/back-monitor/entry.c b/servers/slapd/back-monitor/entry.c index 6901e4455e..b6a39c4eaa 100644 --- a/servers/slapd/back-monitor/entry.c +++ b/servers/slapd/back-monitor/entry.c @@ -163,5 +163,7 @@ monitor_entrypriv_create( void ) mp->mp_flags = MONITOR_F_NONE; mp->mp_cb = NULL; + ldap_pvt_thread_mutex_init( &mp->mp_mutex ); + return mp; } diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 6d05b3212e..9bfec4a583 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -1680,15 +1680,17 @@ fe_aux_operational( * and the backend supports specific operational attributes, * add them to the attribute list */ - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && - ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) ) + if ( !( rs->sr_flags & REP_NO_ENTRYDN ) + && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_entryDN, rs->sr_attrs ) ) ) ) { *ap = slap_operational_entryDN( rs->sr_entry ); ap = &(*ap)->a_next; } - if ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && - ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) ) + if ( !( rs->sr_flags & REP_NO_SUBSCHEMA) + && ( SLAP_OPATTRS( rs->sr_attr_flags ) || ( rs->sr_attrs && + ad_inlist( slap_schema.si_ad_subschemaSubentry, rs->sr_attrs ) ) ) ) { *ap = slap_operational_subschemaSubentry( op->o_bd ); ap = &(*ap)->a_next; diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 926e5be839..da805145d2 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -504,8 +504,13 @@ static ConfigTable config_back_cf_table[] = { { "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC, &syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, - { "threads", "count", 2, 2, 0, ARG_INT|ARG_MAGIC|CFG_THREADS, - &config_generic, "( OLcfgGlAt:66 NAME 'olcThreads' " + { "threads", "count", 2, 2, 0, +#ifdef NO_THREADS + ARG_IGNORED, NULL, +#else + ARG_INT|ARG_MAGIC|CFG_THREADS, &config_generic, +#endif + "( OLcfgGlAt:66 NAME 'olcThreads' " "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, { "timelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC, &config_timelimit, "( OLcfgGlAt:67 NAME 'olcTimeLimit' " @@ -1068,7 +1073,15 @@ config_generic(ConfigArgs *c) { break; case CFG_THREADS: - if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) { + if ( c->value_int < 2 ) { + snprintf( c->msg, sizeof( c->msg ), + "threads=%d smaller than minimum value 2", + c->value_int ); + Debug(LDAP_DEBUG_ANY, "%s: %s.\n", + c->log, c->msg, 0 ); + return 1; + + } else if ( c->value_int > 2 * SLAP_MAX_WORKER_THREADS ) { snprintf( c->msg, sizeof( c->msg ), "warning, threads=%d larger than twice the default (2*%d=%d); YMMV", c->value_int, SLAP_MAX_WORKER_THREADS, 2 * SLAP_MAX_WORKER_THREADS ); diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index feb75edee2..5f01a04362 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -1995,6 +1995,13 @@ connection_init_log_prefix( Operation *op ) } } +static int connection_bind_cleanup_cb( Operation *op, SlapReply *rs ) +{ + op->o_conn->c_sasl_bindop = NULL; + + return SLAP_CB_CONTINUE; +} + static int connection_bind_cb( Operation *op, SlapReply *rs ) { slap_callback *cb = op->o_callback; @@ -2065,6 +2072,7 @@ static void connection_op_queue( Operation *op ) if (tag == LDAP_REQ_BIND) { slap_callback *sc = ch_calloc( 1, sizeof( slap_callback )); sc->sc_response = connection_bind_cb; + sc->sc_cleanup = connection_bind_cleanup_cb; sc->sc_next = op->o_callback; op->o_callback = sc; op->o_conn->c_conn_state = SLAP_C_BINDING; diff --git a/servers/slapd/init.c b/servers/slapd/init.c index 73fe703a0b..053184f797 100644 --- a/servers/slapd/init.c +++ b/servers/slapd/init.c @@ -125,6 +125,8 @@ slap_init( int mode, const char *name ) switch ( slapMode & SLAP_MODE ) { case SLAP_SERVER_MODE: + ldap_pvt_thread_pool_init( &connection_pool, + connection_pool_max, 0); /* FALLTHRU */ case SLAP_TOOL_MODE: @@ -135,9 +137,6 @@ slap_init( int mode, const char *name ) slap_name = name; - ldap_pvt_thread_pool_init( &connection_pool, - connection_pool_max, 0); - ldap_pvt_thread_mutex_init( &entry2str_mutex ); ldap_pvt_thread_mutex_init( &replog_mutex ); diff --git a/servers/slapd/overlays/retcode.c b/servers/slapd/overlays/retcode.c index cad6b86bed..8b09f73361 100644 --- a/servers/slapd/overlays/retcode.c +++ b/servers/slapd/overlays/retcode.c @@ -77,6 +77,8 @@ typedef struct retcode_t { struct berval rd_pdn; struct berval rd_npdn; + int rd_sleep; + retcode_item_t *rd_item; unsigned rd_flags; @@ -202,7 +204,6 @@ retcode_op_internal( Operation *op, SlapReply *rs ) slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; Operation op2 = *op; - SlapReply rs2 = { 0 }; BackendDB db = *op->o_bd; slap_callback sc = { 0 }; retcode_cb_t rdc; @@ -236,7 +237,8 @@ retcode_op_internal( Operation *op, SlapReply *rs ) sc.sc_private = &rdc; op2.o_callback = ≻ - rc = op2.o_bd->be_search( &op2, &rs2 ); + rc = op2.o_bd->be_search( &op2, rs ); + op->o_abandon = op2.o_abandon; filter_free_x( &op2, op2.ors_filter ); ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx ); @@ -259,6 +261,14 @@ retcode_op_func( Operation *op, SlapReply *rs ) slap_callback *cb = NULL; + /* sleep as required */ + if ( rd->rd_sleep < 0 ) { + sleep( rand() % ( - rd->rd_sleep ) ); + + } else if ( rd->rd_sleep > 0 ) { + sleep( rd->rd_sleep ); + } + if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) { if ( RETCODE_INDIR( rd ) ) { switch ( op->o_tag ) { @@ -275,10 +285,18 @@ retcode_op_func( Operation *op, SlapReply *rs ) case LDAP_REQ_SEARCH: if ( op->ors_scope == LDAP_SCOPE_BASE ) { rs->sr_err = retcode_op_internal( op, rs ); - if ( rs->sr_err == SLAP_CB_CONTINUE ) { + switch ( rs->sr_err ) { + case SLAP_CB_CONTINUE: + if ( rs->sr_nentries == 0 ) { + break; + } rs->sr_err = LDAP_SUCCESS; + /* fallthru */ + + default: + send_ldap_result( op, rs ); + break; } - send_ldap_result( op, rs ); return rs->sr_err; } break; @@ -874,6 +892,31 @@ retcode_db_config( } else if ( strcasecmp( argv0, "indir" ) == 0 ) { rd->rd_flags |= RETCODE_FINDIR; + } else if ( strcasecmp( argv0, "sleep" ) == 0 ) { + switch ( argc ) { + case 1: + fprintf( stderr, "%s: line %d: retcode: " + "\"retcode-sleep