]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-bdb/search.c
More for #5860 - if the cache blew past the maxsize, bring it all the way
[openldap] / servers / slapd / back-bdb / search.c
index 77ffb61affdc0a2ff586108642bb235a77005512..1f28e9fda2a161c31d8a2cf6d9420dc6094c91cf 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2000-2007 The OpenLDAP Foundation.
+ * Copyright 2000-2009 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@ static int search_candidates(
        Operation *op,
        SlapReply *rs,
        Entry *e,
-       BDB_LOCKER locker,
+       DB_TXN *txn,
        ID      *ids,
        ID      *scopes );
 
@@ -51,7 +51,7 @@ static Entry * deref_base (
        SlapReply *rs,
        Entry *e,
        Entry **matched,
-       BDB_LOCKER locker,
+       DB_TXN *txn,
        DB_LOCK *lock,
        ID      *tmp,
        ID      *visited )
@@ -101,8 +101,10 @@ static Entry * deref_base (
                        break;
                }
 
-               rs->sr_err = bdb_dn2entry( op, NULL, &ndn, &ei,
-                       0, locker, &lockr );
+               rs->sr_err = bdb_dn2entry( op, txn, &ndn, &ei,
+                       0, &lockr );
+               if ( rs->sr_err == DB_LOCK_DEADLOCK )
+                       return NULL;
 
                if ( ei ) {
                        e = ei->bei_e;
@@ -143,7 +145,7 @@ static int search_aliases(
        Operation *op,
        SlapReply *rs,
        Entry *e,
-       BDB_LOCKER locker,
+       DB_TXN *txn,
        ID *ids,
        ID *scopes,
        ID *stack )
@@ -180,7 +182,7 @@ static int search_aliases(
 
        /* Find all aliases in database */
        BDB_IDL_ZERO( aliases );
-       rs->sr_err = bdb_filter_candidates( op, locker, &af, aliases,
+       rs->sr_err = bdb_filter_candidates( op, txn, &af, aliases,
                curscop, visited );
        if (rs->sr_err != LDAP_SUCCESS) {
                return rs->sr_err;
@@ -202,13 +204,17 @@ static int search_aliases(
                 * to the cumulative list of candidates.
                 */
                BDB_IDL_CPY( curscop, aliases );
-               rs->sr_err = bdb_dn2idl( op, locker, &e->e_nname, BEI(e), subscop,
+               rs->sr_err = bdb_dn2idl( op, txn, &e->e_nname, BEI(e), subscop,
                        subscop2+BDB_IDL_DB_SIZE );
+
                if (first) {
                        first = 0;
                } else {
                        bdb_cache_return_entry_r (bdb, e, &locka);
                }
+               if ( rs->sr_err == DB_LOCK_DEADLOCK )
+                       return rs->sr_err;
+
                BDB_IDL_CPY(subscop2, subscop);
                rs->sr_err = bdb_idl_intersection(curscop, subscop);
                bdb_idl_union( ids, subscop2 );
@@ -220,11 +226,13 @@ static int search_aliases(
                {
                        ei = NULL;
 retry1:
-                       rs->sr_err = bdb_cache_find_id(op, NULL,
-                               ida, &ei, 0, locker, &lockr );
+                       rs->sr_err = bdb_cache_find_id(op, txn,
+                               ida, &ei, 0, &lockr );
                        if (rs->sr_err != LDAP_SUCCESS) {
-                               if ( rs->sr_err == DB_LOCK_DEADLOCK ||
-                                       rs->sr_err == DB_LOCK_NOTGRANTED ) goto retry1;
+                               if ( rs->sr_err == DB_LOCK_DEADLOCK )
+                                       return rs->sr_err;
+                               if ( rs->sr_err == DB_LOCK_NOTGRANTED )
+                                       goto retry1;
                                continue;
                        }
                        a = ei->bei_e;
@@ -239,7 +247,7 @@ retry1:
 
                        /* Actually dereference the alias */
                        BDB_IDL_ZERO(tmp);
-                       a = deref_base( op, rs, a, &matched, locker, &lockr,
+                       a = deref_base( op, rs, a, &matched, txn, &lockr,
                                tmp, visited );
                        if (a) {
                                /* If the target was not already in our current candidates,
@@ -253,6 +261,8 @@ retry1:
                                }
                                bdb_cache_return_entry_r( bdb, a, &lockr);
 
+                       } else if ( rs->sr_err == DB_LOCK_DEADLOCK ) {
+                               return rs->sr_err;
                        } else if (matched) {
                                /* Alias could not be dereferenced, or it deref'd to
                                 * an ID we've already seen. Ignore it.
@@ -286,11 +296,12 @@ nextido:
                 */
                ei = NULL;
 sameido:
-               rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei,
-                       0, locker, &locka );
+               rs->sr_err = bdb_cache_find_id(op, txn, ido, &ei,
+                       0, &locka );
                if ( rs->sr_err != LDAP_SUCCESS ) {
-                       if ( rs->sr_err == DB_LOCK_DEADLOCK ||
-                               rs->sr_err == DB_LOCK_NOTGRANTED )
+                       if ( rs->sr_err == DB_LOCK_DEADLOCK )
+                               return rs->sr_err;
+                       if ( rs->sr_err == DB_LOCK_NOTGRANTED )
                                goto sameido;
                        goto nextido;
                }
@@ -318,23 +329,26 @@ bdb_search( Operation *op, SlapReply *rs )
        int             tentries = 0, nentries = 0;
        int             idflag = 0;
 
-       BDB_LOCKER      locker = 0;
        DB_LOCK         lock;
        struct  bdb_op_info     *opinfo = NULL;
        DB_TXN                  *ltid = NULL;
+       OpExtra *oex;
 
        Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_search) "\n", 0, 0, 0);
        attrs = op->oq_search.rs_attrs;
 
-       opinfo = (struct bdb_op_info *) op->o_private;
+       LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
+               if ( oex->oe_key == bdb )
+                       break;
+       }
+       opinfo = (struct bdb_op_info *) oex;
 
        manageDSAit = get_manageDSAit( op );
 
        if ( opinfo && opinfo->boi_txn ) {
                ltid = opinfo->boi_txn;
-               locker = TXN_ID( ltid );
        } else {
-               rs->sr_err = LOCK_ID( bdb->bi_dbenv, &locker );
+               rs->sr_err = bdb_reader_get( op, bdb->bi_dbenv, &ltid );
 
                switch(rs->sr_err) {
                case 0:
@@ -357,7 +371,7 @@ bdb_search( Operation *op, SlapReply *rs )
 dn2entry_retry:
                /* get entry with reader lock */
                rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei,
-                       1, locker, &lock );
+                       1, &lock );
        }
 
        switch(rs->sr_err) {
@@ -367,18 +381,20 @@ dn2entry_retry:
        case 0:
                e = ei->bei_e;
                break;
+       case DB_LOCK_DEADLOCK:
+               if ( !opinfo ) {
+                       ltid->flags &= ~TXN_DEADLOCK;
+                       goto dn2entry_retry;
+               }
+               opinfo->boi_err = rs->sr_err;
+               /* FALLTHRU */
        case LDAP_BUSY:
                send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" );
-               if ( !opinfo )
-                       LOCK_ID_FREE (bdb->bi_dbenv, locker );
                return LDAP_BUSY;
-       case DB_LOCK_DEADLOCK:
        case DB_LOCK_NOTGRANTED:
                goto dn2entry_retry;
        default:
                send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
-               if ( !opinfo )
-                       LOCK_ID_FREE (bdb->bi_dbenv, locker );
                return rs->sr_err;
        }
 
@@ -388,7 +404,7 @@ dn2entry_retry:
 
                        stub.bv_val = op->o_req_ndn.bv_val;
                        stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1;
-                       e = deref_base( op, rs, matched, &matched, locker, &lock,
+                       e = deref_base( op, rs, matched, &matched, ltid, &lock,
                                candidates, NULL );
                        if ( e ) {
                                build_new_dn( &op->o_req_ndn, &e->e_nname, &stub,
@@ -398,7 +414,7 @@ dn2entry_retry:
                                goto dn2entry_retry;
                        }
                } else if ( e && is_entry_alias( e )) {
-                       e = deref_base( op, rs, e, &matched, locker, &lock,
+                       e = deref_base( op, rs, e, &matched, ltid, &lock,
                                candidates, NULL );
                }
        }
@@ -451,8 +467,6 @@ dn2entry_retry:
 
                send_ldap_result( op, rs );
 
-               if ( !opinfo )
-                       LOCK_ID_FREE (bdb->bi_dbenv, locker );
                if ( rs->sr_ref ) {
                        ber_bvarray_free( rs->sr_ref );
                        rs->sr_ref = NULL;
@@ -518,9 +532,6 @@ dn2entry_retry:
                rs->sr_matched = matched_dn.bv_val;
                send_ldap_result( op, rs );
 
-               if ( !opinfo ) {
-                       LOCK_ID_FREE (bdb->bi_dbenv, locker );
-               }
                ber_bvarray_free( rs->sr_ref );
                rs->sr_ref = NULL;
                ber_memfree( matched_dn.bv_val );
@@ -568,10 +579,20 @@ dn2entry_retry:
                rs->sr_err = base_candidate( op->o_bd, &base, candidates );
 
        } else {
+cand_retry:
                BDB_IDL_ZERO( candidates );
                BDB_IDL_ZERO( scopes );
                rs->sr_err = search_candidates( op, rs, &base,
-                       locker, candidates, scopes );
+                       ltid, candidates, scopes );
+               if ( rs->sr_err == DB_LOCK_DEADLOCK ) {
+                       if ( !opinfo ) {
+                               ltid->flags &= ~TXN_DEADLOCK;
+                               goto cand_retry;
+                       }
+                       opinfo->boi_err = rs->sr_err;
+                       send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" );
+                       return LDAP_BUSY;
+               }
        }
 
        /* start cursor at beginning of candidates.
@@ -674,48 +695,57 @@ loop_begin:
                 * any subsequent entries
                 */
                nentries++;
-               if ( nentries > bdb->bi_cache.c_maxsize && !idflag )
+               if ( nentries > bdb->bi_cache.c_maxsize && !idflag ) {
                        idflag = ID_NOCACHE;
+               }
 
 fetch_entry_retry:
-                       /* get the entry with reader lock */
-                       ei = NULL;
-                       rs->sr_err = bdb_cache_find_id( op, ltid,
-                               id, &ei, idflag, locker, &lock );
+               /* get the entry with reader lock */
+               ei = NULL;
+               rs->sr_err = bdb_cache_find_id( op, ltid,
+                       id, &ei, idflag, &lock );
 
-                       if (rs->sr_err == LDAP_BUSY) {
-                               rs->sr_text = "ldap server busy";
-                               send_ldap_result( op, rs );
-                               goto done;
+               if (rs->sr_err == LDAP_BUSY) {
+                       rs->sr_text = "ldap server busy";
+                       send_ldap_result( op, rs );
+                       goto done;
 
-                       } else if ( rs->sr_err == DB_LOCK_DEADLOCK
-                               || rs->sr_err == DB_LOCK_NOTGRANTED )
-                       {
+               } else if ( rs->sr_err == DB_LOCK_DEADLOCK ) {
+                       if ( !opinfo ) {
+                               ltid->flags &= ~TXN_DEADLOCK;
                                goto fetch_entry_retry;
-                       } else if ( rs->sr_err == LDAP_OTHER ) {
-                               rs->sr_text = "internal error";
-                               send_ldap_result( op, rs );
-                               goto done;
                        }
+                       opinfo->boi_err = rs->sr_err;
+                       send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" );
+                       goto done;
 
-                       if ( ei && rs->sr_err == LDAP_SUCCESS ) {
-                               e = ei->bei_e;
-                       } else {
-                               e = NULL;
-                       }
+               } else if ( rs->sr_err == DB_LOCK_NOTGRANTED )
+               {
+                       goto fetch_entry_retry;
+               } else if ( rs->sr_err == LDAP_OTHER ) {
+                       rs->sr_text = "internal error";
+                       send_ldap_result( op, rs );
+                       goto done;
+               }
 
-                       if ( e == NULL ) {
-                               if( !BDB_IDL_IS_RANGE(candidates) ) {
-                                       /* only complain for non-range IDLs */
-                                       Debug( LDAP_DEBUG_TRACE,
-                                               LDAP_XSTRING(bdb_search)
-                                               ": candidate %ld not found\n",
-                                               (long) id, 0, 0 );
-                               }
+               if ( ei && rs->sr_err == LDAP_SUCCESS ) {
+                       e = ei->bei_e;
+               } else {
+                       e = NULL;
+               }
 
-                               goto loop_continue;
+               if ( e == NULL ) {
+                       if( !BDB_IDL_IS_RANGE(candidates) ) {
+                               /* only complain for non-range IDLs */
+                               Debug( LDAP_DEBUG_TRACE,
+                                       LDAP_XSTRING(bdb_search)
+                                       ": candidate %ld not found\n",
+                                       (long) id, 0, 0 );
                        }
 
+                       goto loop_continue;
+               }
+
                rs->sr_entry = e;
 
                if ( is_entry_subentry( e ) ) {
@@ -823,13 +853,51 @@ fetch_entry_retry:
                if ( !manageDSAit && op->oq_search.rs_scope != LDAP_SCOPE_BASE
                        && is_entry_referral( e ) )
                {
+                       struct bdb_op_info bois;
+                       struct bdb_lock_info blis;
                        BerVarray erefs = get_entry_referrals( op, e );
                        rs->sr_ref = referral_rewrite( erefs, &e->e_name, NULL,
                                op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
                                        ? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
 
+                       /* Must set lockinfo so that entry_release will work */
+                       if (!opinfo) {
+                               bois.boi_oe.oe_key = bdb;
+                               bois.boi_txn = NULL;
+                               bois.boi_err = 0;
+                               bois.boi_acl_cache = op->o_do_not_cache;
+                               bois.boi_flag = BOI_DONTFREE;
+                               bois.boi_locks = &blis;
+                               blis.bli_next = NULL;
+                               LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe,
+                                       oe_next );
+                       } else {
+                               blis.bli_next = opinfo->boi_locks;
+                               opinfo->boi_locks = &blis;
+                       }
+                       blis.bli_id = e->e_id;
+                       blis.bli_lock = lock;
+                       blis.bli_flag = BLI_DONTFREE;
+
+                       rs->sr_flags = REP_ENTRY_MUSTRELEASE;
+
                        send_search_reference( op, rs );
 
+                       if ( blis.bli_flag ) {
+#ifdef SLAP_ZONE_ALLOC
+                               slap_zn_runlock(bdb->bi_cache.c_zctx, e);
+#endif
+                               bdb_cache_return_entry_r(bdb, e, &lock);
+                               if ( opinfo ) {
+                                       opinfo->boi_locks = blis.bli_next;
+                               } else {
+                                       LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe,
+                                               OpExtra, oe_next );
+                               }
+                       }
+                       rs->sr_entry = NULL;
+                       e = NULL;
+
                        ber_bvarray_free( rs->sr_ref );
                        ber_bvarray_free( erefs );
                        rs->sr_ref = NULL;
@@ -860,14 +928,55 @@ fetch_entry_retry:
                        }
 
                        if (e) {
+                               struct bdb_op_info bois;
+                               struct bdb_lock_info blis;
+
+                               /* Must set lockinfo so that entry_release will work */
+                               if (!opinfo) {
+                                       bois.boi_oe.oe_key = bdb;
+                                       bois.boi_txn = NULL;
+                                       bois.boi_err = 0;
+                                       bois.boi_acl_cache = op->o_do_not_cache;
+                                       bois.boi_flag = BOI_DONTFREE;
+                                       bois.boi_locks = &blis;
+                                       blis.bli_next = NULL;
+                                       LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe,
+                                               oe_next );
+                               } else {
+                                       blis.bli_next = opinfo->boi_locks;
+                                       opinfo->boi_locks = &blis;
+                               }
+                               blis.bli_id = e->e_id;
+                               blis.bli_lock = lock;
+                               blis.bli_flag = BLI_DONTFREE;
+
                                /* safe default */
                                rs->sr_attrs = op->oq_search.rs_attrs;
                                rs->sr_operational_attrs = NULL;
                                rs->sr_ctrls = NULL;
-                               rs->sr_flags = 0;
+                               rs->sr_flags = REP_ENTRY_MUSTRELEASE;
                                rs->sr_err = LDAP_SUCCESS;
                                rs->sr_err = send_search_entry( op, rs );
 
+                               /* send_search_entry will usually free it.
+                                * an overlay might leave its own copy here;
+                                * bli_flag will be 0 if lock was already released.
+                                */
+                               if ( blis.bli_flag ) {
+#ifdef SLAP_ZONE_ALLOC
+                                       slap_zn_runlock(bdb->bi_cache.c_zctx, e);
+#endif
+                                       bdb_cache_return_entry_r(bdb, e, &lock);
+                                       if ( opinfo ) {
+                                               opinfo->boi_locks = blis.bli_next;
+                                       } else {
+                                               LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe,
+                                                       OpExtra, oe_next );
+                                       }
+                               }
+                               rs->sr_entry = NULL;
+                               e = NULL;
+
                                switch ( rs->sr_err ) {
                                case LDAP_SUCCESS:      /* entry sent ok */
                                        break;
@@ -875,12 +984,6 @@ fetch_entry_retry:
                                        break;
                                case LDAP_UNAVAILABLE:
                                case LDAP_SIZELIMIT_EXCEEDED:
-#ifdef SLAP_ZONE_ALLOC
-                                       slap_zn_runlock(bdb->bi_cache.c_zctx, e);
-#endif
-                                       bdb_cache_return_entry_r(bdb, e, &lock);
-                                       e = NULL;
-                                       rs->sr_entry = NULL;
                                        if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
                                                rs->sr_ref = rs->sr_v2ref;
                                                send_ldap_result( op, rs );
@@ -926,9 +1029,6 @@ nochange:
        rs->sr_err = LDAP_SUCCESS;
 
 done:
-       if ( !opinfo )
-               LOCK_ID_FREE( bdb->bi_dbenv, locker );
-
        if( rs->sr_v2ref ) {
                ber_bvarray_free( rs->sr_v2ref );
                rs->sr_v2ref = NULL;
@@ -998,7 +1098,7 @@ static void *search_stack( Operation *op )
        void *ret = NULL;
 
        if ( op->o_threadctx ) {
-               ldap_pvt_thread_pool_getkey( op->o_threadctx, search_stack,
+               ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)search_stack,
                        &ret, NULL );
        } else {
                ret = bdb->bi_search_stack;
@@ -1008,7 +1108,7 @@ static void *search_stack( Operation *op )
                ret = ch_malloc( bdb->bi_search_stack_depth * BDB_IDL_UM_SIZE
                        * sizeof( ID ) );
                if ( op->o_threadctx ) {
-                       ldap_pvt_thread_pool_setkey( op->o_threadctx, search_stack,
+                       ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)search_stack,
                                ret, search_stack_free, NULL, NULL );
                } else {
                        bdb->bi_search_stack = ret;
@@ -1021,7 +1121,7 @@ static int search_candidates(
        Operation *op,
        SlapReply *rs,
        Entry *e,
-       BDB_LOCKER locker,
+       DB_TXN *txn,
        ID      *ids,
        ID      *scopes )
 {
@@ -1095,13 +1195,13 @@ static int search_candidates(
        }
 
        if( op->ors_deref & LDAP_DEREF_SEARCHING ) {
-               rc = search_aliases( op, rs, e, locker, ids, scopes, stack );
+               rc = search_aliases( op, rs, e, txn, ids, scopes, stack );
        } else {
-               rc = bdb_dn2idl( op, locker, &e->e_nname, BEI(e), ids, stack );
+               rc = bdb_dn2idl( op, txn, &e->e_nname, BEI(e), ids, stack );
        }
 
        if ( rc == LDAP_SUCCESS ) {
-               rc = bdb_filter_candidates( op, locker, &f, ids,
+               rc = bdb_filter_candidates( op, txn, &f, ids,
                        stack, stack+BDB_IDL_UM_SIZE );
        }
 
@@ -1160,10 +1260,6 @@ parse_paged_cookie( Operation *op, SlapReply *rs )
                        goto done;
                }
 
-       } else {
-               /* Initial request.  Initialize state. */
-               ps->ps_cookie = 0;
-               ps->ps_count = 0;
        }
 
 done:;