]> git.sur5r.net Git - openldap/commitdiff
Changes suggested by Ando.
authorKurt Zeilenga <kurt@openldap.org>
Wed, 5 Apr 2006 00:34:42 +0000 (00:34 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Wed, 5 Apr 2006 00:34:42 +0000 (00:34 +0000)
21 files changed:
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/chain.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/search.c
servers/slapd/back-meta/add.c
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/bind.c
servers/slapd/back-meta/candidates.c
servers/slapd/back-meta/config.c
servers/slapd/back-meta/conn.c
servers/slapd/back-meta/delete.c
servers/slapd/back-meta/init.c
servers/slapd/back-monitor/cache.c
servers/slapd/back-monitor/entry.c
servers/slapd/backend.c
servers/slapd/bconfig.c
servers/slapd/connection.c
servers/slapd/init.c
servers/slapd/overlays/retcode.c
servers/slapd/slap.h

index 2c14022d2fdeba7ec97ef9ba3175f7f5e8f37451..f6c25b2496b8af314de41ca64f2e0984c5261eb0 100644 (file)
@@ -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;
index ed478507eff9bff3c01a0dd49beacc998b8be78d..36edfacd0ef2b5715f5bce6c5d5fc58332dd76a6 100644 (file)
@@ -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;
                }
        }
 
index 5b7816584e9089d3382610328b126bf09089cc4c..779be7697bffba864fece8bf80d826515682fc5a 100644 (file)
@@ -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;
index 6dd8363a19b3a0cb771adb986b98d2ca739a84eb..a00d820b64f6c0ae153eaec865b4fa7852a978de 100644 (file)
@@ -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 ) {
index 2be811f1faad92907173adf33d03a4849e0690d2..e76e2cdf32819e08b042534eecb49752e7262ccd 100644 (file)
@@ -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 );
index 89453b8ec82153f9bd97bf8b5d3aacd2b4fcae82..03187a90e6e7cc75ebfa960f5aafb27f28cd5582 100644 (file)
@@ -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;
 }
index 2cf8369c7ca5fc908fc17fd03958950849ec1563..9d6eba8ab8f216b0dac353d7146f1b950646d8d6 100644 (file)
@@ -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)
  */
index 9f5c0962dae51e0b22c5d3090b58d26a9cbfd318..43f82973782011221749b4faa1922405b8a2c3a9 100644 (file)
@@ -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 );
 }
 
 /*
index 1986ab3bd6f45158343099039b1893463867fa8a..794d1b3a471a80289ee7da64b0f055482d216210 100644 (file)
@@ -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;
+}
index cf26945dfe3a2c5da9b0f908508495541f0fbde2..4e5997a64c6d5474f6d7fa3ca47e2f22c1f91408 100644 (file)
@@ -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 ) {
index 7af76de1993274b5549764b5384f95956bdd6874..657881ca50df5126f4ea764f57585ada0420f4cd 100644 (file)
 #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 );
 }
index f0f5e4259ffe1906b42e6d9e67654f5af5b63743..d904efb90327c21a14f7737747eca732e6706a3e 100644 (file)
@@ -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;
 }
index 6ce783139107d6db698029f3a966c6cbff71492f..b6944c8b4d44de5753e118cd415036625ea1c24a 100644 (file)
@@ -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 );
 }
 
index 071ae06ab968a32352d03c935c491dae64969a0f..89bfe044b49d28ff1bba8f7feec94d993206bbd7 100644 (file)
@@ -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;
index 6901e4455e6102bd79b9f0167206f619a8c2b5a4..b6a39c4eaa5d900255d52721108d23f6b4c35721 100644 (file)
@@ -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;
 }
index 6d05b3212e55ab96a37faf905b16f2e408296a02..9bfec4a583e8736b973e6309b981b4b52af20ad3 100644 (file)
@@ -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;
index 926e5be839514822fbbb2002bb03fd7b6b2bbe52..da805145d2b5474066be024c060bfdf9620ca253 100644 (file)
@@ -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 );
index feb75edee2aa2a42105372a1d7aa3196000a8939..5f01a04362be6de6a37e8394da886225ccbd92f0 100644 (file)
@@ -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;
index 73fe703a0be391f7d4457cd276fd949173b1a865..053184f797d6d3b9280798ad1819ca83a0c0aa9a 100644 (file)
@@ -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 );
 
index cad6b86bed26b3a566e196fd007d368d17800d70..8b09f733613228d0a4047a771ba4bd4003fe8415 100644 (file)
@@ -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 = &sc;
 
-       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 <time>\": missing <time>\n",
+                               fname, lineno );
+                       return 1;
+
+               case 2:
+                       break;
+
+               default:
+                       fprintf( stderr, "%s: line %d: retcode: "
+                               "\"retcode-sleep <time>\": extra cruft after <time>\n",
+                               fname, lineno );
+                       return 1;
+               }
+
+               if ( lutil_atoi( &rd->rd_sleep, argv[ 1 ] ) != 0 ) {
+                       fprintf( stderr, "%s: line %d: retcode: "
+                               "\"retcode-sleep <time>\": unable to parse <time>\n",
+                               fname, lineno );
+                       return 1;
+               }
+
        } else {
                return SLAP_CONF_UNKNOWN;
        }
index 0037828491372976d57505a509f9be5afb21992f..0f2f92d37ec629cd148d83c1dea593ad0ac9247e 100644 (file)
@@ -1992,7 +1992,11 @@ typedef struct slap_rep {
 #define REP_ENTRY_MUSTBEFREED  0x0002U
 #define REP_ENTRY_MUSTRELEASE  0x0004U
 #define REP_MATCHED_MUSTBEFREED        0x0010U
-#define REP_REF_MUSTBEFREED            0x0020U
+#define REP_REF_MUSTBEFREED    0x0020U
+
+#define        REP_NO_ENTRYDN          0x1000U
+#define        REP_NO_SUBSCHEMA        0x2000U
+#define        REP_NO_OPERATIONALS     (REP_NO_ENTRYDN|REP_NO_SUBSCHEMA)
 } SlapReply;
 
 /* short hands for response members */