]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/pcache.c
Merge branch 'mdb.master' of ssh://git-master.openldap.org/~git/git/openldap
[openldap] / servers / slapd / overlays / pcache.c
index 6a4af3bc30719fa12e1664de660cc1072d8c6edf..d27dcb7a0a7e176279f2e84aef65f980d8aec045 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2010 The OpenLDAP Foundation.
+ * Copyright 2003-2011 The OpenLDAP Foundation.
  * Portions Copyright 2003 IBM Corporation.
  * Portions Copyright 2003-2009 Symas Corporation.
  * All rights reserved.
@@ -84,6 +84,7 @@ typedef struct cached_query_s {
        time_t                                          expiry_time;    /* time till the query is considered invalid */
        time_t                                          refresh_time;   /* time till the query is refreshed */
        time_t                                          bindref_time;   /* time till the bind is refreshed */
+       int                                             bind_refcnt;    /* number of bind operation referencing this query */
        unsigned long                   answerable_cnt; /* how many times it was answerable */
        int                                             refcnt; /* references since last refresh */
        ldap_pvt_thread_mutex_t         answerable_cnt_mutex;
@@ -445,7 +446,7 @@ ftemp_attrs( struct berval *ftemp, struct berval *template,
        AttributeDescription **descs = NULL;
        char *temp2;
 
-       temp2 = ch_malloc( ftemp->bv_len );
+       temp2 = ch_malloc( ftemp->bv_len + 1 );
        p1 = ftemp->bv_val;
        t1 = temp2;
 
@@ -598,7 +599,7 @@ url2query(
        LDAPURLDesc     *lud = NULL;
        struct berval   base,
                        tempstr = BER_BVNULL,
-                       uuid;
+                       uuid = BER_BVNULL;
        int             attrset;
        time_t          expiry_time;
        time_t          refresh_time;
@@ -674,9 +675,11 @@ url2query(
                        }
 
                        ber_str2bv( &lud->lud_exts[ i ][ STRLENOF( "x-uuid=" ) ], 0, 0, &tmpUUID );
-                       rc = syn_UUID->ssyn_pretty( syn_UUID, &tmpUUID, &uuid, NULL );
-                       if ( rc != LDAP_SUCCESS ) {
-                               goto error;
+                       if ( !BER_BVISEMPTY( &tmpUUID ) ) {
+                               rc = syn_UUID->ssyn_pretty( syn_UUID, &tmpUUID, &uuid, NULL );
+                               if ( rc != LDAP_SUCCESS ) {
+                                       goto error;
+                               }
                        }
                        got |= GOT_UUID;
 
@@ -919,38 +922,49 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 )
        int rc, weight1, weight2;
 
        switch( f1->f_choice ) {
-       case LDAP_FILTER_PRESENT:
+       case LDAP_FILTER_AND:
+       case LDAP_FILTER_OR:
                weight1 = 0;
                break;
+       case LDAP_FILTER_PRESENT:
+               weight1 = 1;
+               break;
        case LDAP_FILTER_EQUALITY:
        case LDAP_FILTER_GE:
        case LDAP_FILTER_LE:
-               weight1 = 1;
+               weight1 = 2;
                break;
        default:
-               weight1 = 2;
+               weight1 = 3;
        }
        switch( f2->f_choice ) {
-       case LDAP_FILTER_PRESENT:
+       case LDAP_FILTER_AND:
+       case LDAP_FILTER_OR:
                weight2 = 0;
                break;
+       case LDAP_FILTER_PRESENT:
+               weight2 = 1;
+               break;
        case LDAP_FILTER_EQUALITY:
        case LDAP_FILTER_GE:
        case LDAP_FILTER_LE:
-               weight2 = 1;
+               weight2 = 2;
                break;
        default:
-               weight2 = 2;
+               weight2 = 3;
        }
        rc = weight1 - weight2;
        if ( !rc ) {
                switch( weight1 ) {
                case 0:
+                       rc = pcache_filter_cmp( f1->f_and, f2->f_and );
                        break;
                case 1:
-                       rc = lex_bvcmp( &f1->f_av_value, &f2->f_av_value );
                        break;
                case 2:
+                       rc = lex_bvcmp( &f1->f_av_value, &f2->f_av_value );
+                       break;
+               case 3:
                        if ( f1->f_choice == LDAP_FILTER_SUBSTRINGS ) {
                                rc = 0;
                                if ( !BER_BVISNULL( &f1->f_sub_initial )) {
@@ -991,7 +1005,7 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 )
                        }
                        break;
                }
-               if ( !rc ) {
+               while ( !rc ) {
                        f1 = f1->f_next;
                        f2 = f2->f_next;
                        if ( f1 || f2 ) {
@@ -1000,12 +1014,10 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 )
                                else if ( !f2 )
                                        rc = 1;
                                else {
-                                       while ( f1->f_choice == LDAP_FILTER_AND || f1->f_choice == LDAP_FILTER_OR )
-                                               f1 = f1->f_and;
-                                       while ( f2->f_choice == LDAP_FILTER_AND || f2->f_choice == LDAP_FILTER_OR )
-                                               f2 = f2->f_and;
                                        rc = pcache_filter_cmp( f1, f2 );
                                }
+                       } else {
+                               break;
                        }
                }
        }
@@ -1016,7 +1028,7 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 )
 static int pcache_query_cmp( const void *v1, const void *v2 )
 {
        const CachedQuery *q1 = v1, *q2 =v2;
-       return pcache_filter_cmp( q1->first, q2->first );
+       return pcache_filter_cmp( q1->filter, q2->filter );
 }
 
 /* add query on top of LRU list */
@@ -1248,6 +1260,11 @@ filter_first( Filter *f )
        return f;
 }
 
+typedef struct fstack {
+       struct fstack *fs_next;
+       Filter *fs_fs;
+       Filter *fs_fi;
+} fstack;
 
 static CachedQuery *
 find_filter( Operation *op, Avlnode *root, Filter *inputf, Filter *first )
@@ -1259,6 +1276,7 @@ find_filter( Operation *op, Avlnode *root, Filter *inputf, Filter *first )
        int ret, rc, dir;
        Avlnode *ptr;
        CachedQuery cq, *qc;
+       fstack *stack = NULL, *fsp;
 
        cq.filter = inputf;
        cq.first = first;
@@ -1334,6 +1352,14 @@ nextpass:                        eqpass = 1;
                        switch (fs->f_choice) {
                        case LDAP_FILTER_OR:
                        case LDAP_FILTER_AND:
+                               if ( fs->f_next ) {
+                                       /* save our stack position */
+                                       fsp = op->o_tmpalloc(sizeof(fstack), op->o_tmpmemctx);
+                                       fsp->fs_next = stack;
+                                       fsp->fs_fs = fs->f_next;
+                                       fsp->fs_fi = fi->f_next;
+                                       stack = fsp;
+                               }
                                fs = fs->f_and;
                                fi = fi->f_and;
                                res=1;
@@ -1383,6 +1409,14 @@ nextpass:                        eqpass = 1;
                        default:
                                break;
                        }
+                       if (!fs && !fi && stack) {
+                               /* pop the stack */
+                               fsp = stack;
+                               stack = fsp->fs_next;
+                               fs = fsp->fs_fs;
+                               fi = fsp->fs_fi;
+                               op->o_tmpfree(fsp, op->o_tmpmemctx);
+                       }
                } while((res) && (fi != NULL) && (fs != NULL));
 
                if ( res )
@@ -1550,7 +1584,9 @@ add_query(
        }
        new_cached_query->expiry_time = now + ttl;
        new_cached_query->refresh_time = ttr;
+       new_cached_query->bindref_time = 0;
 
+       new_cached_query->bind_refcnt = 0;
        new_cached_query->answerable_cnt = 0;
        new_cached_query->refcnt = 1;
        ldap_pvt_thread_mutex_init(&new_cached_query->answerable_cnt_mutex);
@@ -1599,6 +1635,8 @@ add_query(
                templ->no_of_queries++;
        } else {
                ldap_pvt_thread_mutex_destroy(&new_cached_query->answerable_cnt_mutex);
+               if (wlock)
+                       ldap_pvt_thread_rdwr_wunlock(&new_cached_query->rwlock);
                ldap_pvt_thread_rdwr_destroy( &new_cached_query->rwlock );
                ch_free( new_cached_query );
                new_cached_query = find_filter( op, qbase->scopes[query->scope],
@@ -1609,16 +1647,16 @@ add_query(
        Debug( pcache_debug, "TEMPLATE %p QUERIES++ %d\n",
                        (void *) templ, templ->no_of_queries, 0 );
 
-       Debug( pcache_debug, "Unlock AQ index = %p \n",
-                       (void *) templ, 0, 0 );
-       ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
-
        /* Adding on top of LRU list  */
        if ( rc == 0 ) {
                ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
                add_query_on_top(qm, new_cached_query);
                ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
        }
+       Debug( pcache_debug, "Unlock AQ index = %p \n",
+                       (void *) templ, 0, 0 );
+       ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
+
        return rc == 0 ? new_cached_query : NULL;
 }
 
@@ -2030,11 +2068,7 @@ fetch_queryId_cb( Operation *op, SlapReply *rs )
        }
 
        /* clear entry if required */
-       if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
-               entry_free( rs->sr_entry );
-               rs->sr_entry = NULL;
-               rs->sr_flags ^= REP_ENTRY_MUSTBEFREED;
-       }
+       rs_flush_entry( op, rs, (slap_overinst *) op->o_bd->bd_info );
 
        return rc;
 }
@@ -2394,8 +2428,10 @@ over:;
                                switch ( si->caching_reason ) {
                                case PC_POSITIVE:
                                        cache_entries( op, &qc->q_uuid );
-                                       if ( si->pbi )
+                                       if ( si->pbi ) {
+                                               qc->bind_refcnt++;
                                                si->pbi->bi_cq = qc;
+                                       }
                                        break;
 
                                case PC_SIZELIMIT:
@@ -2596,10 +2632,20 @@ pc_bind_save( Operation *op, SlapReply *rs )
                bindcacheinfo *bci = op->o_callback->sc_private;
                slap_overinst *on = bci->on;
                cache_manager *cm = on->on_bi.bi_private;
-
-               Operation op2 = *op;
-               if ( pc_setpw( &op2, &op->orb_cred, cm ) == LDAP_SUCCESS )
-                       bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr;
+               CachedQuery *qc = bci->qc;
+               int delete = 0;
+
+               ldap_pvt_thread_rdwr_wlock( &qc->rwlock );
+               if ( qc->bind_refcnt-- ) {
+                       Operation op2 = *op;
+                       if ( pc_setpw( &op2, &op->orb_cred, cm ) == LDAP_SUCCESS )
+                               bci->qc->bindref_time = op->o_time + bci->qc->qtemp->bindttr;
+               } else {
+                       bci->qc = NULL;
+                       delete = 1;
+               }
+               ldap_pvt_thread_rdwr_wunlock( &qc->rwlock );
+               if ( delete ) free_query(qc);
        }
        return SLAP_CB_CONTINUE;
 }
@@ -2862,6 +2908,7 @@ pcache_op_bind(
 
        /* OK, just bind locally */
        if ( bi.bi_flags & BI_HASHED ) {
+               int delete = 0;
                BackendDB *be = op->o_bd;
                op->o_bd = &cm->db;
 
@@ -2872,6 +2919,12 @@ pcache_op_bind(
                        op->o_conn->c_authz_cookie = cm->db.be_private;
                }
                op->o_bd = be;
+               ldap_pvt_thread_rdwr_wlock( &bi.bi_cq->rwlock );
+               if ( !bi.bi_cq->bind_refcnt-- ) {
+                       delete = 1;
+               }
+               ldap_pvt_thread_rdwr_wunlock( &bi.bi_cq->rwlock );
+               if ( delete ) free_query( bi.bi_cq );
                return rs->sr_err;
        }
 
@@ -2891,6 +2944,8 @@ pcache_op_bind(
        return SLAP_CB_CONTINUE;
 }
 
+static slap_response refresh_merge;
+
 static int
 pcache_op_search(
        Operation       *op,
@@ -2929,7 +2984,8 @@ pcache_op_search(
        cm->db.be_acl = op->o_bd->be_acl;
 
        {
-               /* See if we're processing a Bind request */
+               /* See if we're processing a Bind request
+                * or a cache refresh */
                slap_callback *cb = op->o_callback;
 
                for ( ; cb; cb=cb->sc_next ) {
@@ -2937,6 +2993,10 @@ pcache_op_search(
                                pbi = cb->sc_private;
                                break;
                        }
+                       if ( cb->sc_response == refresh_merge ) {
+                               /* This is a refresh, do not search the cache */
+                               return SLAP_CB_CONTINUE;
+                       }
                }
        }
 
@@ -3005,15 +3065,17 @@ pcache_op_search(
                        answerable->answerable_cnt, 0, 0 );
                ldap_pvt_thread_mutex_unlock( &answerable->answerable_cnt_mutex );
 
-               ldap_pvt_thread_rdwr_rlock(&answerable->rwlock);
+               ldap_pvt_thread_rdwr_wlock(&answerable->rwlock);
                if ( BER_BVISNULL( &answerable->q_uuid )) {
                        /* No entries cached, just an empty result set */
                        i = rs->sr_err = 0;
                        send_ldap_result( op, rs );
                } else {
                        /* Let Bind know we used a cached query */
-                       if ( pbi )
+                       if ( pbi ) {
+                               answerable->bind_refcnt++;
                                pbi->bi_cq = answerable;
+                       }
 
                        op->o_bd = &cm->db;
                        if ( cm->response_cb == PCACHE_RESPONSE_CB_TAIL ) {
@@ -3036,7 +3098,7 @@ pcache_op_search(
                        }
                        i = cm->db.bd_info->bi_op_search( op, rs );
                }
-               ldap_pvt_thread_rdwr_runlock(&answerable->rwlock);
+               ldap_pvt_thread_rdwr_wunlock(&answerable->rwlock);
                /* locked by qtemp->qcfunc (query_containment) */
                ldap_pvt_thread_rdwr_runlock(&qtemp->t_rwlock);
                op->o_bd = save_bd;
@@ -3264,6 +3326,7 @@ refresh_merge( Operation *op, SlapReply *rs )
                        slap_mods_free( modlist, 1 );
                        /* mods is NULL if there are no changes */
                        if ( mods ) {
+                               SlapReply rs2 = { REP_RESULT };
                                struct berval dn = op->o_req_dn;
                                struct berval ndn = op->o_req_ndn;
                                op->o_tag = LDAP_REQ_MODIFY;
@@ -3271,7 +3334,9 @@ refresh_merge( Operation *op, SlapReply *rs )
                                op->o_req_dn = rs->sr_entry->e_name;
                                op->o_req_ndn = rs->sr_entry->e_nname;
                                op->o_callback = &cb;
-                               op->o_bd->be_modify( op, rs );
+                               op->o_bd->be_modify( op, &rs2 );
+                               rs->sr_err = rs2.sr_err;
+                               rs_assert_done( &rs2 );
                                slap_mods_free( mods, 1 );
                                op->o_req_dn = dn;
                                op->o_req_ndn = ndn;
@@ -3325,9 +3390,9 @@ refresh_purge( Operation *op, SlapReply *rs )
 }
 
 static int
-refresh_query( Operation *op, SlapReply *rs, CachedQuery *query,
-       slap_overinst *on )
+refresh_query( Operation *op, CachedQuery *query, slap_overinst *on )
 {
+       SlapReply rs = {REP_RESULT};
        slap_callback cb = { 0 };
        refresh_info ri = { 0 };
        char filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(pcacheQueryID=)" ) ];
@@ -3365,7 +3430,7 @@ refresh_query( Operation *op, SlapReply *rs, CachedQuery *query,
        op->ors_attrsonly = 0;
 
        op->o_bd = on->on_info->oi_origdb;
-       rc = op->o_bd->be_search( op, rs );
+       rc = op->o_bd->be_search( op, &rs );
        if ( rc ) {
                op->o_bd = ri.ri_be;
                goto leave;
@@ -3388,17 +3453,17 @@ refresh_query( Operation *op, SlapReply *rs, CachedQuery *query,
        attrs[ 0 ].an_name = ad_queryId->ad_cname;
        op->ors_attrs = attrs;
        op->ors_attrsonly = 0;
-       rs->sr_entry = NULL;
-       rs->sr_nentries = 0;
-       rc = op->o_bd->be_search( op, rs );
+       rs_reinit( &rs, REP_RESULT );
+       rc = op->o_bd->be_search( op, &rs );
        if ( rc ) goto leave;
 
        while (( dn = ri.ri_dels )) {
                op->o_req_dn = dn->dn;
                op->o_req_ndn = dn->dn;
+               rs_reinit( &rs, REP_RESULT );
                if ( dn->delete ) {
                        op->o_tag = LDAP_REQ_DELETE;
-                       op->o_bd->be_delete( op, rs );
+                       op->o_bd->be_delete( op, &rs );
                } else {
                        Modifications mod;
                        struct berval vals[2];
@@ -3416,7 +3481,7 @@ refresh_query( Operation *op, SlapReply *rs, CachedQuery *query,
 
                        op->o_tag = LDAP_REQ_MODIFY;
                        op->orm_modlist = &mod;
-                       op->o_bd->be_modify( op, rs );
+                       op->o_bd->be_modify( op, &rs );
                }
                ri.ri_dels = dn->next;
                op->o_tmpfree( dn, op->o_tmpmemctx );
@@ -3441,7 +3506,6 @@ consistency_check(
        OperationBuffer opbuf;
        Operation *op;
 
-       SlapReply rs = {REP_RESULT};
        CachedQuery *query, *qprev;
        int return_val, pause = PCACHE_CC_PAUSED;
        QueryTemplate *templ;
@@ -3487,7 +3551,7 @@ consistency_check(
                                if ( query->refcnt )
                                        query->expiry_time = op->o_time + templ->ttl;
                                if ( query->expiry_time > op->o_time ) {
-                                       refresh_query( op, &rs, query, on );
+                                       refresh_query( op, query, on );
                                        continue;
                                }
                        }
@@ -3505,8 +3569,8 @@ consistency_check(
                                        Debug( pcache_debug, "Unlock CR index = %p\n",
                                                        (void *) templ, 0, 0 );
                                }
-                               ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
                                if ( !rem ) {
+                                       ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
                                        continue;
                                }
                                ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
@@ -3528,7 +3592,15 @@ consistency_check(
                                        "STALE QUERY REMOVED, CACHE ="
                                        "%d entries\n",
                                        cm->cur_entries, 0, 0 );
-                               free_query(query);
+                               ldap_pvt_thread_rdwr_wlock( &query->rwlock );
+                               if ( query->bind_refcnt-- ) {
+                                       rem = 0;
+                               } else {
+                                       rem = 1;
+                               }
+                               ldap_pvt_thread_rdwr_wunlock( &query->rwlock );
+                               if ( rem ) free_query(query);
+                               ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
                        } else if ( !templ->ttr && query->expiry_time > ttl ) {
                                /* We don't need to check for refreshes, and this
                                 * query's expiry is too new, and all subsequent queries
@@ -3763,13 +3835,23 @@ pc_cf_gen( ConfigArgs *c )
                                /* count the attr length */
                                for ( attr_name = qm->attr_sets[i].attrs;
                                        attr_name->an_name.bv_val; attr_name++ )
+                               {
                                        bv.bv_len += attr_name->an_name.bv_len + 1;
+                                       if ( attr_name->an_desc &&
+                                                       ( attr_name->an_desc->ad_flags & SLAP_DESC_TEMPORARY ) ) {
+                                               bv.bv_len += STRLENOF("undef:");
+                                       }
+                               }
 
                                bv.bv_val = ch_malloc( bv.bv_len+1 );
                                ptr = lutil_strcopy( bv.bv_val, c->cr_msg );
                                for ( attr_name = qm->attr_sets[i].attrs;
                                        attr_name->an_name.bv_val; attr_name++ ) {
                                        *ptr++ = ' ';
+                                       if ( attr_name->an_desc &&
+                                                       ( attr_name->an_desc->ad_flags & SLAP_DESC_TEMPORARY ) ) {
+                                               ptr = lutil_strcopy( ptr, "undef:" );
+                                       }
                                        ptr = lutil_strcopy( ptr, attr_name->an_name.bv_val );
                                }
                                ber_bvarray_add( &c->rvalue_vals, &bv );
@@ -4025,7 +4107,12 @@ pc_cf_gen( ConfigArgs *c )
                                        all_op = 1;
                                        BER_BVSTR( &attr_name->an_name, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
                                } else {
-                                       if ( slap_str2ad( c->argv[i], &attr_name->an_desc, &text ) ) {
+                                       if ( strncasecmp( c->argv[i], "undef:", STRLENOF("undef:") ) == 0 ) {
+                                               struct berval bv;
+                                               ber_str2bv( c->argv[i] + STRLENOF("undef:"), 0, 0, &bv );
+                                               attr_name->an_desc = slap_bv2tmp_ad( &bv, NULL );
+
+                                       } else if ( slap_str2ad( c->argv[i], &attr_name->an_desc, &text ) ) {
                                                strcpy( c->cr_msg, text );
                                                Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
                                                ch_free( qm->attr_sets[num].attrs );
@@ -4246,7 +4333,7 @@ pc_bind_fail:
                        i = 0;
                        while ((eq = strchr(eq, '=' ))) {
                                eq++;
-                               if ( eq[1] == ')' )
+                               if ( eq[0] == ')' )
                                        i++;
                        }
                        bv.bv_len = temp->bindftemp.bv_len + i;
@@ -4524,7 +4611,7 @@ pcache_db_open2(
                        OperationBuffer opbuf;
                        Operation       *op;
                        slap_callback   cb = { 0 };
-                       SlapReply       rs = { 0 };
+                       SlapReply       rs = { REP_RESULT };
                        BerVarray       vals = NULL;
                        Filter          f = { 0 }, f2 = { 0 };
                        AttributeAssertion      ava = ATTRIBUTEASSERTION_INIT;
@@ -4589,8 +4676,8 @@ pcache_db_open2(
                        op->ors_scope = LDAP_SCOPE_SUBTREE;
                        op->ors_attrs = slap_anlist_no_attrs;
 
+                       rs_reinit( &rs, REP_RESULT );
                        op->o_callback->sc_response = pcache_cachedquery_count_cb;
-                       rs.sr_nentries = 0;
                        op->o_callback->sc_private = &rs.sr_nentries;
 
                        rc = op->o_bd->be_search( op, &rs );
@@ -4719,6 +4806,7 @@ pcache_db_close(
                connection_fake_init2( &conn, &opbuf, thrctx, 0 );
                op = &opbuf.ob_op;
 
+                mod.sml_numvals = 0;
                if ( qm->templates != NULL ) {
                        for ( tm = qm->templates; tm != NULL; tm = tm->qmnext ) {
                                for ( qc = tm->query; qc; qc = qc->next ) {
@@ -4726,6 +4814,7 @@ pcache_db_close(
 
                                        if ( query2url( op, qc, &bv, 0 ) == 0 ) {
                                                ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx );
+                                               mod.sml_numvals++;
                                        }
                                }
                        }
@@ -4752,7 +4841,6 @@ pcache_db_close(
                mod.sml_type = ad_cachedQueryURL->ad_cname;
                mod.sml_values = vals;
                mod.sml_nvalues = NULL;
-                mod.sml_numvals = 1;
                mod.sml_next = NULL;
                Debug( pcache_debug,
                        "%sSETTING CACHED QUERY URLS\n",
@@ -4792,7 +4880,19 @@ pcache_db_close(
                free( tm );
        }
 
-       for ( i=0; i<cm->numattrsets; i++ ) {
+       for ( i = 0; i < cm->numattrsets; i++ ) {
+               int j;
+
+               /* Account of LDAP_NO_ATTRS */
+               if ( !qm->attr_sets[i].count ) continue;
+
+               for ( j = 0; !BER_BVISNULL( &qm->attr_sets[i].attrs[j].an_name ); j++ ) {
+                       if ( qm->attr_sets[i].attrs[j].an_desc &&
+                                       ( qm->attr_sets[i].attrs[j].an_desc->ad_flags &
+                                         SLAP_DESC_TEMPORARY ) ) {
+                               slap_sl_mfuncs.bmf_free( qm->attr_sets[i].attrs[j].an_desc, NULL );
+                       }
+               }
                free( qm->attr_sets[i].attrs );
        }
        free( qm->attr_sets );
@@ -5522,7 +5622,7 @@ pcache_monitor_db_close( BackendDB *be )
 
                if ( mi && &mi->bi_extra ) {
                        mbe = mi->bi_extra;
-                       mbe->unregister_entry_callback( NULL,
+                       mbe->unregister_entry_callback( &cm->monitor_ndn,
                                (monitor_callback_t *)cm->monitor_cb,
                                NULL, 0, NULL );
                }