]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/pcache.c
ITS#6951 Fix two buffersize issue in "pcacheBind" config processing
[openldap] / servers / slapd / overlays / pcache.c
index eac0f6205d5ceeb3eaac79e4f285d3c992125a21..62477513bdbbaacf56813b9af044b2d0c68554b9 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2009 The OpenLDAP Foundation.
+ * Copyright 2003-2011 The OpenLDAP Foundation.
  * Portions Copyright 2003 IBM Corporation.
  * Portions Copyright 2003-2009 Symas Corporation.
  * All rights reserved.
@@ -346,7 +346,6 @@ add_query(
 static int
 remove_query_data(
        Operation       *op,
-       SlapReply       *rs,
        struct berval   *query_uuid );
 
 /*
@@ -446,7 +445,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;
 
@@ -599,7 +598,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;
@@ -675,9 +674,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;
 
@@ -752,11 +753,10 @@ url2query(
        /* ignore expired queries */
        if ( expiry_time <= slap_get_time()) {
                Operation       op2 = *op;
-               SlapReply       rs2 = { 0 };
 
                memset( &op2.oq_search, 0, sizeof( op2.oq_search ) );
 
-               (void)remove_query_data( &op2, &rs2, &uuid );
+               (void)remove_query_data( &op2, &uuid );
 
                rc = 0;
 
@@ -768,6 +768,10 @@ url2query(
                }
                query.scope = lud->lud_scope;
                query.filter = str2filter( lud->lud_filter );
+               if ( query.filter == NULL ) {
+                       rc = -1;
+                       goto error;
+               }
 
                tempstr.bv_val = ch_malloc( strlen( lud->lud_filter ) + 1 );
                tempstr.bv_len = 0;
@@ -823,6 +827,7 @@ static int
 merge_entry(
        Operation               *op,
        Entry                   *e,
+       int                     dup,
        struct berval*          query_uuid )
 {
        int             rc;
@@ -836,6 +841,8 @@ merge_entry(
 
        slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
 
+       if ( dup )
+               e = entry_dup( e );
        attr = e->e_attrs;
        e->e_attrs = NULL;
 
@@ -858,6 +865,7 @@ merge_entry(
 
        if ( rc != LDAP_SUCCESS ) {
                if ( rc == LDAP_ALREADY_EXISTS ) {
+                       rs_reinit( &sreply, REP_RESULT );
                        slap_entry2mods( e, &modlist, &text, textbuf, textlen );
                        modlist->sml_op = LDAP_MOD_ADD;
                        op->o_tag = LDAP_REQ_MODIFY;
@@ -877,7 +885,7 @@ merge_entry(
                }
        } else {
                if ( op->ora_e == e )
-                       be_entry_release_w( op, e );
+                       entry_free( e );
                rc = 1;
        }
 
@@ -1592,6 +1600,10 @@ add_query(
                templ->query = new_cached_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],
                                                        query->filter, first );
@@ -1739,7 +1751,6 @@ remove_func (
 static int
 remove_query_data(
        Operation       *op,
-       SlapReply       *rs,
        struct berval   *query_uuid )
 {
        struct query_info       *qi, *qnext;
@@ -1750,8 +1761,6 @@ remove_query_data(
        slap_callback cb = { NULL, remove_func, NULL, NULL };
        int deleted = 0;
 
-       sreply.sr_entry = NULL;
-       sreply.sr_nentries = 0;
        op->ors_filterstr.bv_len = snprintf(filter_str, sizeof(filter_str),
                "(%s=%s)", ad_queryId->ad_cname.bv_val, query_uuid->bv_val);
        filter.f_ava = &ava;
@@ -1784,6 +1793,7 @@ remove_query_data(
 
                op->o_req_dn = qi->xdn;
                op->o_req_ndn = qi->xdn;
+               rs_reinit( &sreply, REP_RESULT );
 
                if ( qi->del ) {
                        Debug( pcache_debug, "DELETING ENTRY TEMPLATE=%s\n",
@@ -1962,7 +1972,6 @@ struct search_info {
 static void
 remove_query_and_data(
        Operation       *op,
-       SlapReply       *rs,
        cache_manager   *cm,
        struct berval   *uuid )
 {
@@ -1975,7 +1984,7 @@ remove_query_and_data(
                Debug( pcache_debug,
                        "Removing query UUID %s\n",
                        uuid->bv_val, 0, 0 );
-               return_val = remove_query_data( op, rs, uuid );
+               return_val = remove_query_data( op, uuid );
                Debug( pcache_debug,
                        "QUERY REMOVED, SIZE=%d\n",
                        return_val, 0, 0);
@@ -2025,11 +2034,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;
 }
@@ -2048,7 +2053,6 @@ pcache_remove_entries_from_cache(
        OperationBuffer opbuf;
        Operation       op2;
        slap_callback   sc = { 0 };
-       SlapReply       rs = { REP_RESULT };
        Filter          f = { 0 };
        char            filtbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(entryUUID=)" ) ];
        AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
@@ -2095,6 +2099,7 @@ pcache_remove_entries_from_cache(
 
        for ( s = 0; !BER_BVISNULL( &entryUUIDs[ s ] ); s++ ) {
                BerVarray       vals = NULL;
+               SlapReply       rs = { REP_RESULT };
 
                op->ors_filterstr.bv_len = snprintf( filtbuf, sizeof( filtbuf ),
                        "(entryUUID=%s)", entryUUIDs[ s ].bv_val );
@@ -2113,7 +2118,7 @@ pcache_remove_entries_from_cache(
                        for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
                                struct berval   val = vals[ i ];
 
-                               remove_query_and_data( op, &rs, cm, &val );
+                               remove_query_and_data( op, cm, &val );
 
                                if ( !BER_BVISNULL( &val ) && val.bv_val != vals[ i ].bv_val ) {
                                        ch_free( val.bv_val );
@@ -2138,12 +2143,11 @@ pcache_remove_query_from_cache(
        struct berval   *queryid )
 {
        Operation       op2 = *op;
-       SlapReply       rs2 = { 0 };
 
        op2.o_bd = &cm->db;
 
        /* remove the selected query */
-       remove_query_and_data( &op2, &rs2, cm, queryid );
+       remove_query_and_data( &op2, cm, queryid );
 
        return LDAP_SUCCESS;
 }
@@ -2234,7 +2238,7 @@ pcache_remove_entry_queries_from_cache(
                for ( i = 0; !BER_BVISNULL( &vals[ i ] ); i++ ) {
                        struct berval   val = vals[ i ];
 
-                       remove_query_and_data( op, &rs, cm, &val );
+                       remove_query_and_data( op, cm, &val );
 
                        if ( !BER_BVISNULL( &val ) && val.bv_val != vals[ i ].bv_val ) {
                                ch_free( val.bv_val );
@@ -2250,7 +2254,6 @@ pcache_remove_entry_queries_from_cache(
 static int
 cache_entries(
        Operation       *op,
-       SlapReply       *rs,
        struct berval *query_uuid )
 {
        struct search_info *si = op->o_callback->sc_private;
@@ -2282,10 +2285,10 @@ cache_entries(
                e->e_private = NULL;
                while ( cm->cur_entries > (cm->max_entries) ) {
                        BER_BVZERO( &crp_uuid );
-                       remove_query_and_data( op_tmp, rs, cm, &crp_uuid );
+                       remove_query_and_data( op_tmp, cm, &crp_uuid );
                }
 
-               return_val = merge_entry(op_tmp, e, query_uuid);
+               return_val = merge_entry(op_tmp, e, 0, query_uuid);
                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                cm->cur_entries += return_val;
                Debug( pcache_debug,
@@ -2382,8 +2385,7 @@ over:;
                                        entry_free(si->head);
                                }
                        }
-                       op->o_callback = op->o_callback->sc_next;
-                       op->o_tmpfree( cb, op->o_tmpmemctx );
+
                } else if ( si->caching_reason != PC_IGNORE ) {
                        CachedQuery *qc = qm->addfunc(op, qm, &si->query,
                                si->qtemp, si->caching_reason, 1 );
@@ -2391,7 +2393,7 @@ over:;
                        if ( qc != NULL ) {
                                switch ( si->caching_reason ) {
                                case PC_POSITIVE:
-                                       cache_entries( op, rs, &qc->q_uuid );
+                                       cache_entries( op, &qc->q_uuid );
                                        if ( si->pbi )
                                                si->pbi->bi_cq = qc;
                                        break;
@@ -2439,6 +2441,9 @@ over:;
                } else {
                        filter_free( si->query.filter );
                }
+
+               op->o_callback = op->o_callback->sc_next;
+               op->o_tmpfree( cb, op->o_tmpmemctx );
        }
 
        return SLAP_CB_CONTINUE;
@@ -2471,7 +2476,14 @@ pcache_response(
                        } else if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED
                                && si->qtemp->limitttl )
                        {
+                               Entry *e;
+
                                si->caching_reason = PC_SIZELIMIT;
+                               for (;si->head; si->head=e) {
+                                       e = si->head->e_private;
+                                       si->head->e_private = NULL;
+                                       entry_free(si->head);
+                               }
                        }
 
                } else if ( si->qtemp->negttl && !si->count && !si->over &&
@@ -2598,7 +2610,7 @@ pc_bind_attrs( Operation *op, Entry *e, QueryTemplate *temp,
 {
        int i, len = 0;
        struct berval *vals, pres = BER_BVC("*");
-       char *p1, *p2, *t1;
+       char *p1, *p2;
        Attribute *a;
 
        vals = op->o_tmpalloc( temp->bindnattrs * sizeof( struct berval ),
@@ -2630,7 +2642,14 @@ pc_bind_attrs( Operation *op, Entry *e, QueryTemplate *temp,
        }
        *p2 = '\0';
        op->o_tmpfree( vals, op->o_tmpmemctx );
-       return str2filter_x( op, fbv->bv_val );
+
+       /* FIXME: are we sure str2filter_x can't fail?
+        * caller needs to check */
+       {
+               Filter *f = str2filter_x( op, fbv->bv_val );
+               assert( f != NULL );
+               return f;
+       }
 }
 
 /* Check if the requested entry is from the cache and has a valid
@@ -2997,14 +3016,24 @@ pcache_op_search(
                                pbi->bi_cq = answerable;
 
                        op->o_bd = &cm->db;
-#if 0
                        if ( cm->response_cb == PCACHE_RESPONSE_CB_TAIL ) {
+                               slap_callback cb;
                                /* The cached entry was already processed by any
                                 * other overlays, so don't let it get processed again.
+                                *
+                                * This loop removes over_back_response from the stack.
                                 */
-                               op->o_callback = NULL;
+                               if ( overlay_callback_after_backover( op, &cb, 0) == 0 ) {
+                                       slap_callback **scp;
+                                       for ( scp = &op->o_callback; *scp != NULL;
+                                               scp = &(*scp)->sc_next ) {
+                                               if ( (*scp)->sc_next == &cb ) {
+                                                       *scp = cb.sc_next;
+                                                       break;
+                                               }
+                                       }
+                               }
                        }
-#endif
                        i = cm->db.bd_info->bi_op_search( op, rs );
                }
                ldap_pvt_thread_rdwr_runlock(&answerable->rwlock);
@@ -3089,19 +3118,30 @@ get_attr_set(
        query_manager* qm,
        int num )
 {
-       int i;
+       int i = 0;
        int count = 0;
 
        if ( attrs ) {
-               for ( ; attrs[count].an_name.bv_val; count++ );
+               for ( ; attrs[i].an_name.bv_val; i++ ) {
+                       /* only count valid attribute names
+                        * (searches ignore others, this overlay does the same) */
+                       if ( attrs[i].an_desc ) {
+                               count++;
+                       }
+               }
        }
 
-       /* recognize a single "*" or a "1.1" */
-       if ( count == 0 ) {
+       /* recognize default or explicit single "*" */
+       if ( ! attrs ||
+               ( i == 1 && bvmatch( &attrs[0].an_name, slap_bv_all_user_attrs ) ) )
+       {
                count = 1;
                attrs = slap_anlist_all_user_attributes;
 
-       } else if ( count == 1 && bvmatch( &attrs[0].an_name, slap_bv_no_attrs ) ) {
+       /* recognize implicit (no valid attributes) or explicit single "1.1" */
+       } else if ( count == 0 ||
+               ( i == 1 && bvmatch( &attrs[0].an_name, slap_bv_no_attrs ) ) )
+       {
                count = 0;
                attrs = NULL;
        }
@@ -3122,6 +3162,8 @@ get_attr_set(
                }
 
                for ( a2 = attrs; a2->an_name.bv_val; a2++ ) {
+                       if ( !a2->an_desc && !bvmatch( &a2->an_name, slap_bv_all_user_attrs ) ) continue;
+
                        if ( !an_find( qm->attr_sets[i].attrs, &a2->an_name ) ) {
                                found = 0;
                                break;
@@ -3176,7 +3218,6 @@ refresh_merge( Operation *op, SlapReply *rs )
 {
        if ( rs->sr_type == REP_SEARCH ) {
                refresh_info *ri = op->o_callback->sc_private;
-               BackendDB *be = op->o_bd;
                Entry *e;
                dnlist *dnl;
                slap_callback *ocb;
@@ -3190,7 +3231,7 @@ refresh_merge( Operation *op, SlapReply *rs )
                        /* No local entry, just add it. FIXME: we are not checking
                         * the cache entry limit here
                         */
-                        merge_entry( op, rs->sr_entry, &ri->ri_q->q_uuid );
+                        merge_entry( op, rs->sr_entry, 1, &ri->ri_q->q_uuid );
                } else {
                        /* Entry exists, update it */
                        Entry ne;
@@ -3223,6 +3264,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;
@@ -3230,7 +3272,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;
@@ -3284,9 +3328,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=)" ) ];
@@ -3324,7 +3368,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;
@@ -3347,17 +3391,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];
@@ -3375,7 +3419,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 );
@@ -3400,7 +3444,6 @@ consistency_check(
        OperationBuffer opbuf;
        Operation *op;
 
-       SlapReply rs = {REP_RESULT};
        CachedQuery *query, *qprev;
        int return_val, pause = PCACHE_CC_PAUSED;
        QueryTemplate *templ;
@@ -3446,7 +3489,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;
                                }
                        }
@@ -3474,7 +3517,7 @@ consistency_check(
                                if ( BER_BVISNULL( &query->q_uuid ))
                                        return_val = 0;
                                else
-                                       return_val = remove_query_data(op, &rs, &query->q_uuid);
+                                       return_val = remove_query_data(op, &query->q_uuid);
                                Debug( pcache_debug, "STALE QUERY REMOVED, SIZE=%d\n",
                                                        return_val, 0, 0 );
                                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
@@ -3722,13 +3765,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 );
@@ -3984,7 +4037,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 );
@@ -4205,7 +4263,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;
@@ -4377,9 +4435,13 @@ pcache_db_init(
        cm->check_cacheability = 0;
        cm->response_cb = PCACHE_RESPONSE_CB_TAIL;
        cm->defer_db_open = 1;
+       cm->cache_binds = 0;
        cm->cc_period = 1000;
        cm->cc_paused = 0;
        cm->cc_arg = NULL;
+#ifdef PCACHE_MONITOR
+       cm->monitor_cb = NULL;
+#endif /* PCACHE_MONITOR */
 
        qm->attr_sets = NULL;
        qm->templates = NULL;
@@ -4479,13 +4541,13 @@ 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;
                        AttributeName   attrs[ 2 ] = {{{ 0 }}};
 
-                       connection_fake_init( &conn, &opbuf, thrctx );
+                       connection_fake_init2( &conn, &opbuf, thrctx, 0 );
                        op = &opbuf.ob_op;
 
                        op->o_bd = &cm->db;
@@ -4544,8 +4606,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 );
@@ -4671,9 +4733,10 @@ pcache_db_close(
 
                thrctx = ldap_pvt_thread_pool_context();
 
-               connection_fake_init( &conn, &opbuf, thrctx );
+               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 ) {
@@ -4681,6 +4744,7 @@ pcache_db_close(
 
                                        if ( query2url( op, qc, &bv, 0 ) == 0 ) {
                                                ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx );
+                                               mod.sml_numvals++;
                                        }
                                }
                        }
@@ -4707,7 +4771,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",
@@ -4747,7 +4810,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 );
@@ -5076,6 +5151,10 @@ pcache_exop_query_delete(
        op->o_req_dn = op->o_req_ndn;
 
        op->o_bd = select_backend( &op->o_req_ndn, 0 );
+       if ( op->o_bd == NULL ) {
+               send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT,
+                       "no global superior knowledge" );
+       }
        rs->sr_err = backend_check_restrictions( op, rs,
                (struct berval *)&pcache_exop_QUERY_DELETE );
        if ( rs->sr_err != LDAP_SUCCESS ) {
@@ -5194,6 +5273,20 @@ pcache_op_extended( Operation *op, SlapReply *rs )
        return SLAP_CB_CONTINUE;
 }
 
+static int
+pcache_entry_release( Operation  *op, Entry *e, int rw )
+{
+       slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+       cache_manager   *cm = on->on_bi.bi_private;
+       BackendDB *db = op->o_bd;
+       int rc;
+
+       op->o_bd = &cm->db;
+       rc = be_entry_release_rw( op, e, rw );
+       op->o_bd = db;
+       return rc;
+}
+
 #ifdef PCACHE_MONITOR
 
 static int
@@ -5459,7 +5552,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 );
                }
@@ -5580,6 +5673,7 @@ pcache_initialize()
 #endif /* PCACHE_CONTROL_PRIVDB */
        pcache.on_bi.bi_extended = pcache_op_extended;
 
+       pcache.on_bi.bi_entry_release_rw = pcache_entry_release;
        pcache.on_bi.bi_chk_controls = pcache_chk_controls;
 
        pcache.on_bi.bi_cf_ocs = pcocs;