]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/pcache.c
disable referral rewrite in default suffix massage
[openldap] / servers / slapd / overlays / pcache.c
index 8b2d6a7dadd792d85f23485105d253078d674875..3b667e5380175c13fbb37fbde40bbba5ca7500de 100644 (file)
@@ -29,7 +29,6 @@
 #include <ac/time.h>
 
 #include "slap.h"
-#include "ldap_pvt.h"
 #include "lutil.h"
 #include "ldap_rq.h"
 
@@ -39,6 +38,7 @@
 typedef struct Query_s {
        Filter*         filter;         /* Search Filter */
        AttributeName*  attrs;          /* Projected attributes */
+       AttributeName*  save_attrs;     /* original attributes, saved for response */
        struct berval   base;           /* Search Base */
        int             scope;          /* Search scope */
 } Query;
@@ -117,6 +117,11 @@ typedef struct cache_manager_s {
        int     max_entries;                    /* max number of entries cached */
         int     num_entries_limit;             /* max # of entries in a cacheable query */
 
+       char    response_cb;                    /* install the response callback
+                                                * at the tail of the callback list */
+#define PCACHE_RESPONSE_CB_HEAD        0
+#define PCACHE_RESPONSE_CB_TAIL        1
+
        int     cc_period;              /* interval between successive consistency checks (sec) */
        int     cc_paused;
        void    *cc_arg;
@@ -205,7 +210,7 @@ static int base_scope_compare(
        int scope_stored,
        int scope_incoming      )
 {
-       struct berval pdn_incoming = { 0, NULL };
+       struct berval pdn_incoming = BER_BVNULL;
 
        if (scope_stored < scope_incoming)
                return 0;
@@ -254,13 +259,8 @@ add_query_on_top (query_manager* qm, CachedQuery* qc)
 
        qc->lru_down = top;
        qc->lru_up = NULL;
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Base of added query = %s\n",
-                       q->base.bv_val, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Base of added query = %s\n",
                        q->base.bv_val, 0, 0 );
-#endif
 }
 
 /* remove_query from LRU list */
@@ -515,13 +515,8 @@ query_containment(query_manager *qm,
 
        MatchingRule* mrule = NULL;
        if (inputf != NULL) {
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "Lock QC index = %d\n",
-                               template_index, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY, "Lock QC index = %d\n",
                                template_index, 0, 0 );
-#endif
                ldap_pvt_thread_rdwr_rlock(&(templa[template_index].t_rwlock));
                for(qc=templa[template_index].query; qc != NULL; qc= qc->next) {
                        q = (Query*)qc;
@@ -551,15 +546,9 @@ query_containment(query_manager *qm,
                                                        &(fs->f_ava->aa_value), &text);
                                                if (rc != LDAP_SUCCESS) {
                                                        ldap_pvt_thread_rdwr_runlock(&(templa[template_index].t_rwlock));
-#ifdef NEW_LOGGING
-                                                       LDAP_LOG( BACK_META, DETAIL1,
-                                                       "Unlock: Exiting QC index=%d\n",
-                                                       template_index, 0, 0 );
-#else
                                                        Debug( LDAP_DEBUG_ANY,
                                                        "Unlock: Exiting QC index=%d\n",
                                                        template_index, 0, 0 );
-#endif
                                                        return 0;
                                                }
                                        }
@@ -628,15 +617,9 @@ query_containment(query_manager *qm,
                                }
                        }
                }
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1,
-                       "Not answerable: Unlock QC index=%d\n",
-                       template_index, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY,
                        "Not answerable: Unlock QC index=%d\n",
                        template_index, 0, 0 );
-#endif
                ldap_pvt_thread_rdwr_runlock(&(templa[template_index].t_rwlock));
        }
        return 0;
@@ -674,13 +657,8 @@ static void add_query(
        new_cached_query->lru_up = NULL;
        new_cached_query->lru_down = NULL;
        new_cached_query->expiry_time = slap_get_time() + templ->ttl;
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Added query expires at %ld\n",
-                       (long) new_cached_query->expiry_time, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Added query expires at %ld\n",
                        (long) new_cached_query->expiry_time, 0, 0 );
-#endif
        new_query = (Query*)new_cached_query;
 
        ber_dupbv(&new_query->base, &query->base);
@@ -689,13 +667,8 @@ static void add_query(
        new_query->attrs = query->attrs;
 
        /* Adding a query    */
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Lock AQ index = %d\n",
-                       template_index, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Lock AQ index = %d\n",
                        template_index, 0, 0 );
-#endif
        ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
        if (templ->query == NULL)
                templ->query_last = new_cached_query;
@@ -705,21 +678,11 @@ static void add_query(
        new_cached_query->prev = NULL;
        templ->query = new_cached_query;
        templ->no_of_queries++;
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "TEMPLATE %d QUERIES++ %d\n",
-                       template_index, templ->no_of_queries, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES++ %d\n",
                        template_index, templ->no_of_queries, 0 );
-#endif
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Unlock AQ index = %d \n",
-                       template_index, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Unlock AQ index = %d \n",
                        template_index, 0, 0 );
-#endif
        ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
 
        /* Adding on top of LRU list  */
@@ -760,15 +723,9 @@ static void cache_replacement(query_manager* qm, struct berval *result)
        result->bv_len = 0;
 
        if (!bottom) {
-#ifdef NEW_LOGGING
-               LDAP_LOG ( BACK_META, DETAIL1,
-                       "Cache replacement invoked without "
-                       "any query in LRU list\n", 0, 0, 0 );
-#else
                Debug ( LDAP_DEBUG_ANY,
                        "Cache replacement invoked without "
                        "any query in LRU list\n", 0, 0, 0 );
-#endif
                return;
        }
 
@@ -779,25 +736,12 @@ static void cache_replacement(query_manager* qm, struct berval *result)
        *result = bottom->q_uuid;
        bottom->q_uuid.bv_val = NULL;
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n", temp_id, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n", temp_id, 0, 0 );
-#endif
        ldap_pvt_thread_rdwr_wlock(&(qm->templates[temp_id].t_rwlock));
        remove_from_template(bottom, (qm->templates+temp_id));
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "TEMPLATE %d QUERIES-- %d\n",
-               temp_id, qm->templates[temp_id].no_of_queries, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
                temp_id, qm->templates[temp_id].no_of_queries, 0 );
-#endif
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n", temp_id, 0, 0 );
-#else
        Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n", temp_id, 0, 0 );
-#endif
        ldap_pvt_thread_rdwr_wunlock(&(qm->templates[temp_id].t_rwlock));
        free_query(bottom);
 }
@@ -869,8 +813,8 @@ remove_query_data (
        op->o_req_ndn = op->o_bd->be_nsuffix[0];
        op->ors_scope = LDAP_SCOPE_SUBTREE;
        op->ors_deref = LDAP_DEREF_NEVER;
-       op->ors_slimit = 0;
-       op->ors_tlimit = 0;
+       op->ors_slimit = SLAP_NO_LIMIT;
+       op->ors_tlimit = SLAP_NO_LIMIT;
        op->ors_filter = &filter;
        op->ors_filterstr.bv_val = filter_str;
        op->ors_filterstr.bv_len = strlen(filter_str);
@@ -886,14 +830,8 @@ remove_query_data (
                op->o_req_ndn = qi->xdn;
 
                if ( qi->del) {
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                               "DELETING ENTRY TEMPLATE=%s\n",
-                               query_uuid->bv_val, 0, 0 );
-#else
                        Debug( LDAP_DEBUG_ANY, "DELETING ENTRY TEMPLATE=%s\n",
                                query_uuid->bv_val, 0, 0 );
-#endif
 
                        op->o_tag = LDAP_REQ_DELETE;
 
@@ -910,17 +848,12 @@ remove_query_data (
                        mod.sml_op = LDAP_MOD_DELETE;
                        mod.sml_desc = ad_queryid;
                        mod.sml_type = ad_queryid->ad_cname;
-                       mod.sml_bvalues = vals;
+                       mod.sml_values = vals;
+                       mod.sml_nvalues = NULL;
                        mod.sml_next = NULL;
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                               "REMOVING TEMP ATTR : TEMPLATE=%s\n",
-                               query_uuid->bv_val, 0, 0 );
-#else
                        Debug( LDAP_DEBUG_ANY,
                                "REMOVING TEMP ATTR : TEMPLATE=%s\n",
                                query_uuid->bv_val, 0, 0 );
-#endif
 
                        op->orm_modlist = &mod;
 
@@ -1072,7 +1005,7 @@ cache_entries(
        cache_manager *cm = on->on_bi.bi_private;
        query_manager*          qm = cm->qm;
        int             i;
-       int             return_val;
+       int             return_val = 0;
        Entry           *e;
        struct berval   crp_uuid;
        char            uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
@@ -1085,77 +1018,38 @@ cache_entries(
        op_tmp.o_dn = cm->db.be_rootdn;
        op_tmp.o_ndn = cm->db.be_rootndn;
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
-                       uuidbuf, 0, 0 );
-#else /* !NEW_LOGGING */
        Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
                        uuidbuf, 0, 0 );
-#endif /* !NEW_LOGGING */
 
        for ( e=si->head; e; e=si->head ) {
                si->head = e->e_private;
                e->e_private = NULL;
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
-                               0, 0, 0 );
-#else /* !NEW_LOGGING */
                Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
-#endif /* !NEW_LOGGING */
                ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
-#else /* !NEW_LOGGING */
                Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
-#endif /* !NEW_LOGGING */
                while ( cm->cur_entries > (cm->max_entries) ) {
                                qm->crfunc(qm, &crp_uuid);
                                if (crp_uuid.bv_val) {
-#ifdef NEW_LOGGING
-                                       LDAP_LOG( BACK_META, DETAIL1,
-                                               "Removing query UUID %s\n",
-                                               crp_uuid.bv_val, 0, 0 );
-#else /* !NEW_LOGGING */
                                        Debug( LDAP_DEBUG_ANY,
                                                "Removing query UUID %s\n",
                                                crp_uuid.bv_val, 0, 0 );
-#endif /* !NEW_LOGGING */
                                        return_val = remove_query_data(&op_tmp, rs, &crp_uuid);
-#ifdef NEW_LOGGING
-                                       LDAP_LOG( BACK_META, DETAIL1,
-                                               "QUERY REMOVED, SIZE=%d\n",
-                                               return_val, 0, 0);
-#else /* !NEW_LOGGING */
                                        Debug( LDAP_DEBUG_ANY,
                                                "QUERY REMOVED, SIZE=%d\n",
                                                return_val, 0, 0);
-#endif /* !NEW_LOGGING */
                                        ldap_pvt_thread_mutex_lock(
                                                        &cm->cache_mutex );
                                        cm->cur_entries -= return_val;
                                        cm->num_cached_queries--;
-#ifdef NEW_LOGGING
-                                       LDAP_LOG( BACK_META, DETAIL1,
-                                               "STORED QUERIES = %lu\n",
-                                               cm->num_cached_queries, 0, 0 );
-#else /* !NEW_LOGGING */
                                        Debug( LDAP_DEBUG_ANY,
                                                "STORED QUERIES = %lu\n",
                                                cm->num_cached_queries, 0, 0 );
-#endif /* !NEW_LOGGING */
                                        ldap_pvt_thread_mutex_unlock(
                                                        &cm->cache_mutex );
-#ifdef NEW_LOGGING
-                                       LDAP_LOG( BACK_META, DETAIL1,
-                                               "QUERY REMOVED, CACHE ="
-                                               "%d entries\n",
-                                               cm->cur_entries, 0, 0 );
-#else /* !NEW_LOGGING */
                                        Debug( LDAP_DEBUG_ANY,
                                                "QUERY REMOVED, CACHE ="
                                                "%d entries\n",
                                                cm->cur_entries, 0, 0 );
-#endif /* !NEW_LOGGING */
                                }
                }
 
@@ -1163,27 +1057,16 @@ cache_entries(
                ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                cm->cur_entries += return_val;
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1,
-                       "ENTRY ADDED/MERGED, CACHED ENTRIES=%d\n",
-                       cm->cur_entries, 0, 0 );
-#else /* !NEW_LOGGING */
                Debug( LDAP_DEBUG_ANY,
                        "ENTRY ADDED/MERGED, CACHED ENTRIES=%d\n",
                        cm->cur_entries, 0, 0 );
-#endif /* !NEW_LOGGING */
                return_val = 0;
                ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
        }
        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
        cm->num_cached_queries++;
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
-                       cm->num_cached_queries, 0, 0 );
-#else /* !NEW_LOGGING */
        Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
                        cm->num_cached_queries, 0, 0 );
-#endif /* !NEW_LOGGING */
        ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
 
        return return_val;
@@ -1224,8 +1107,17 @@ proxy_cache_response(
                                si->tail = NULL;
                        }
                }
-       } else if ( rs->sr_type == REP_RESULT && !si->over ) {
-               if ( cache_entries( op, rs, &uuid ) == 0) {
+
+               if (rs->sr_attrs != op->ors_attrs ) {
+                       op->o_tmpfree( rs->sr_attrs, op->o_tmpmemctx );
+               }
+               rs->sr_attrs = si->query.save_attrs;
+               op->o_tmpfree( op->ors_attrs, op->o_tmpmemctx );
+               op->ors_attrs = si->query.save_attrs;
+               si->query.save_attrs = NULL;
+
+       } else if ( rs->sr_type == REP_RESULT ) {
+               if ( si->count && cache_entries( op, rs, &uuid ) == 0 ) {
                        qm->addfunc(qm, &si->query, si->template_id, &uuid);
                        /* If the consistency checker suspended itself,
                         * wake it back up
@@ -1239,6 +1131,9 @@ proxy_cache_response(
                                ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
                        }
                }
+
+               /* free self */
+               op->o_callback->sc_cleanup = slap_freeself_cb;
        }
        return SLAP_CB_CONTINUE;
 }
@@ -1334,19 +1229,15 @@ proxy_cache_search(
                return SLAP_CB_CONTINUE;
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
-                                       tempstr.bv_val, 0, 0 );
-#else /* !NEW_LOGGING */
        Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
                                        tempstr.bv_val, 0, 0 );
-#endif /* !NEW_LOGGING */
 
        /* find attr set */
        attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets);
 
        query.filter = op->ors_filter;
        query.attrs = op->ors_attrs;
+       query.save_attrs = NULL;
        query.base = op->o_req_ndn;
        query.scope = op->ors_scope;
 
@@ -1360,14 +1251,8 @@ proxy_cache_search(
                                cacheable = 1;
                                template_id = i;
                        }
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL2,
-                                       "Entering QC, querystr = %s\n",
-                                       op->ors_filterstr.bv_val, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
                                        op->ors_filterstr.bv_val, 0, 0 );
-#endif /* !NEW_LOGGING */
                        answerable = (*(qm->qcfunc))(qm, &query, i);
 
                        if (answerable)
@@ -1376,27 +1261,27 @@ proxy_cache_search(
        }
        op->o_tmpfree( tempstr.bv_val, op->o_tmpmemctx );
 
+       query.save_attrs = op->ors_attrs;
+       query.attrs = NULL;
+
        if (answerable) {
-               BackendDB *be = op->o_bd;
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "QUERY ANSWERABLE\n", 0, 0, 0 );
-#else /* !NEW_LOGGING */
+               /* Need to clear the callbacks of the original operation,
+                * in case there are other overlays */
+               BackendDB       *save_bd = op->o_bd;
+               slap_callback   *save_cb = op->o_callback;
+
                Debug( LDAP_DEBUG_ANY, "QUERY ANSWERABLE\n", 0, 0, 0 );
-#endif /* !NEW_LOGGING */
                free(filter_attrs);
                ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
                op->o_bd = &cm->db;
+               op->o_callback = NULL;
                i = cm->db.bd_info->bi_op_search( op, rs );
-               op->o_bd = be;
+               op->o_bd = save_bd;
+               op->o_callback = save_cb;
                return i;
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
-                               0, 0, 0 );
-#else /* !NEW_LOGGING */
        Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
-#endif /* !NEW_LOGGING */
 
        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
        if (cm->num_cached_queries >= cm->max_queries) {
@@ -1405,23 +1290,20 @@ proxy_cache_search(
        ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
 
        if (cacheable) {
-               slap_callback *cb;
-               struct search_info *si;
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1,
-                       "QUERY CACHEABLE\n", 0, 0, 0 );
-#else /* !NEW_LOGGING */
+               slap_callback           *cb;
+               struct search_info      *si;
+
                Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
-#endif /* !NEW_LOGGING */
                query.filter = str2filter(op->ors_filterstr.bv_val);
                if (op->ors_attrs) {
-                       for ( count=0; op->ors_attrs[ count ].an_name.bv_val; count++ ) {
-                               if ( op->ors_attrs[count].an_desc == slap_schema.si_ad_objectClass )
+                       for ( count = 0; !BER_BVISNULL( &op->ors_attrs[ count ].an_name ); count++ ) {
+                               if ( op->ors_attrs[count].an_desc == slap_schema.si_ad_objectClass ) {
                                        oc_attr_absent = 0;
+                               }
                        }
-                       query.attrs = (AttributeName*)ch_malloc( ( count + 1 + oc_attr_absent )
-                                                                       *sizeof(AttributeName));
-                       for ( count=0; op->ors_attrs[ count ].an_name.bv_val; count++ ) {
+                       query.attrs = (AttributeName *)ch_malloc( ( count + 1 + oc_attr_absent )
+                                                                       *sizeof(AttributeName) );
+                       for ( count = 0; !BER_BVISNULL( &op->ors_attrs[ count ].an_name ); count++ ) {
                                ber_dupbv( &query.attrs[count].an_name, &op->ors_attrs[count].an_name );
                                query.attrs[count].an_desc = op->ors_attrs[count].an_desc;
                        }
@@ -1434,10 +1316,9 @@ proxy_cache_search(
                        query.attrs[ count ].an_name.bv_val = NULL;
                        query.attrs[ count ].an_name.bv_len = 0;
                }
-               op->o_tmpfree(op->ors_attrs, op->o_tmpmemctx);
                add_filter_attrs(op, &op->ors_attrs, query.attrs, filter_attrs);
+
                cb = op->o_tmpalloc( sizeof(*cb) + sizeof(*si), op->o_tmpmemctx);
-               cb->sc_next = op->o_callback;
                cb->sc_response = proxy_cache_response;
                cb->sc_cleanup = NULL;
                cb->sc_private = (cb+1);
@@ -1450,16 +1331,25 @@ proxy_cache_search(
                si->count = 0;
                si->head = NULL;
                si->tail = NULL;
-               op->o_callback = cb;
+
+               if ( cm->response_cb == PCACHE_RESPONSE_CB_HEAD ) {
+                       cb->sc_next = op->o_callback;
+                       op->o_callback = cb;
+
+               } else {
+                       slap_callback           **pcb;
+
+                       /* need to move the callback at the end, in case other
+                        * overlays are present, so that the final entry is
+                        * actually cached */
+                       cb->sc_next = NULL;
+                       for ( pcb = &op->o_callback; *pcb; pcb = &(*pcb)->sc_next );
+                       *pcb = cb;
+               }
+
        } else {
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1,
-                                       "QUERY NOT CACHEABLE\n",
-                                       0, 0, 0);
-#else /* !NEW_LOGGING */
                Debug( LDAP_DEBUG_ANY, "QUERY NOT CACHEABLE\n",
                                        0, 0, 0);
-#endif /* !NEW_LOGGING */
        }
 
        free(filter_attrs);
@@ -1546,78 +1436,43 @@ consistency_check(
                        ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
                        remove_query(qm, query);
                        ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
-                                       i, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
                                        i, 0, 0 );
-#endif /* !NEW_LOGGING */
                        ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
                        remove_from_template(query, templ);
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                                       "TEMPLATE %d QUERIES-- %d\n",
-                                       i, templ->no_of_queries, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
                                        i, templ->no_of_queries, 0 );
-#endif /* !NEW_LOGGING */
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
-                                       i, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
                                        i, 0, 0 );
-#endif /* !NEW_LOGGING */
                        ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
                        return_val = remove_query_data(&op, &rs, &query->q_uuid);
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                                       "STALE QUERY REMOVED, SIZE=%d\n",
-                                       return_val, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
                                                return_val, 0, 0 );
-#endif /* !NEW_LOGGING */
                        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                        cm->cur_entries -= return_val;
                        cm->num_cached_queries--;
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
-                                       cm->num_cached_queries, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
                                        cm->num_cached_queries, 0, 0 );
-#endif /* !NEW_LOGGING */
                        ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                               "STALE QUERY REMOVED, CACHE ="
-                               "%d entries\n",
-                               cm->cur_entries, 0, 0 );
-#else /* !NEW_LOGGING */
                        Debug( LDAP_DEBUG_ANY,
                                "STALE QUERY REMOVED, CACHE ="
                                "%d entries\n",
                                cm->cur_entries, 0, 0 );
-#endif /* !NEW_LOGGING */
                        query_prev = query;
                        query = query->prev;
                        free_query(query_prev);
                }
                ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
        }
-       /* If there were no queries, defer processing for a while */
-       if ( pause ) {
-               ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
-               cm->cc_paused = 1;
-               if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) {
-                       ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
-               }
-               ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, 1 );
-               ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
+       ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
+       if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) {
+               ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask );
        }
+       /* If there were no queries, defer processing for a while */
+       cm->cc_paused = pause;
+       ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, pause );
+
+       ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
        return NULL;
 }
 
@@ -1635,16 +1490,23 @@ proxy_cache_config(
        char            **argv
 )
 {
-       slap_overinst *on = (slap_overinst *)be->bd_info;
+       slap_overinst   *on = (slap_overinst *)be->bd_info;
        cache_manager*  cm = on->on_bi.bi_private;
        query_manager*  qm = cm->qm;
        QueryTemplate*  temp;
        AttributeName*  attr_name;
        AttributeName*  attrarray;
        const char*     text=NULL;
+       char            *save_argv0 = NULL;
 
        int             index, i;
        int             num;
+       int             rc = 0;
+
+       if ( strncasecmp( argv[0], "proxycache-", STRLENOF( "proxycache-" ) ) == 0 ) {
+               save_argv0 = argv[0];
+               argv[0] += STRLENOF( "proxycache-" );
+       }
 
        if ( strcasecmp( argv[0], "proxycache" ) == 0 ) {
                if ( argc < 6 ) {
@@ -1676,15 +1538,9 @@ proxy_cache_config(
 
                cm->num_entries_limit = atoi( argv[4] );
                cm->cc_period = atoi( argv[5] );
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1,
-                               "Total # of attribute sets to be cached = %d\n",
-                               cm->numattrsets, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY,
                                "Total # of attribute sets to be cached = %d\n",
                                cm->numattrsets, 0, 0 );
-#endif
                qm->attr_sets = ( struct attr_set * )ch_malloc( cm->numattrsets *
                                                sizeof( struct attr_set ));
                for ( i = 0; i < cm->numattrsets; i++ ) {
@@ -1697,13 +1553,8 @@ proxy_cache_config(
                                "<index> <attributes>\"\n", fname, lineno );
                        return( 1 );
                }
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "Attribute Set # %d\n",
-                               atoi( argv[1] ), 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY, "Attribute Set # %d\n",
                                atoi( argv[1] ), 0, 0 );
-#endif
                if (atoi(argv[1]) >= cm->numattrsets) {
                        fprintf( stderr, "%s; line %d index out of bounds \n",
                                        fname, lineno );
@@ -1716,13 +1567,8 @@ proxy_cache_config(
                                                (argc-1) * sizeof( AttributeName ));
                        attr_name = qm->attr_sets[index].attrs;
                        for ( i = 2; i < argc; i++ ) {
-#ifdef NEW_LOGGING
-                               LDAP_LOG( BACK_META, DETAIL1, "\t %s\n",
-                                               argv[i], 0, 0 );
-#else
                                Debug( LDAP_DEBUG_ANY, "\t %s\n",
                                                argv[i], 0, 0 );
-#endif
                                ber_str2bv( argv[i], 0, 1,
                                                &attr_name->an_name);
                                attr_name->an_desc = NULL;
@@ -1741,15 +1587,9 @@ proxy_cache_config(
                        return( 1 );
                }
                if (( i = atoi( argv[2] )) >= cm->numattrsets ) {
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                                       "%s: line %d, template index invalid\n",
-                                       fname, lineno, 0 );
-#else
                        Debug( LDAP_DEBUG_ANY,
                                        "%s: line %d, template index invalid\n",
                                        fname, lineno, 0 );
-#endif
                        return 1;
                }
                num = cm->numtemplates;
@@ -1763,55 +1603,62 @@ proxy_cache_config(
                temp->ttl = atoi( argv[3] );
                temp->no_of_queries = 0;
                if ( argv[1] == NULL ) {
-#ifdef NEW_LOGGING
-                       LDAP_LOG( BACK_META, DETAIL1,
-                                       "Templates string not specified "
-                                       "for template %d\n", num, 0, 0 );
-#else
                        Debug( LDAP_DEBUG_ANY,
                                        "Templates string not specified "
                                        "for template %d\n", num, 0, 0 );
-#endif
                        return 1;
                }
                ber_str2bv( argv[1], 0, 1, &temp->querystr );
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "Template:\n", 0, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY, "Template:\n", 0, 0, 0 );
-#endif
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "  query template: %s\n",
-                               temp->querystr.bv_val, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY, "  query template: %s\n",
                                temp->querystr.bv_val, 0, 0 );
-#endif
                temp->attr_set_index = i;
-#ifdef NEW_LOGGING
-               LDAP_LOG( BACK_META, DETAIL1, "  attributes: \n", 0, 0, 0 );
-#else
                Debug( LDAP_DEBUG_ANY, "  attributes: \n", 0, 0, 0 );
-#endif
                if ( ( attrarray = qm->attr_sets[i].attrs ) != NULL ) {
                        for ( i=0; attrarray[i].an_name.bv_val; i++ )
-#ifdef NEW_LOGGING
-                               LDAP_LOG( BACK_META, DETAIL1, "\t%s\n",
-                                       attrarray[i].an_name.bv_val, 0, 0 );
-#else
                                Debug( LDAP_DEBUG_ANY, "\t%s\n",
                                        attrarray[i].an_name.bv_val, 0, 0 );
-#endif
                }
                temp++; 
                temp->querystr.bv_val = NULL;
                cm->numtemplates++;
+
+       } else if ( strcasecmp( argv[0], "response-callback" ) == 0 ) {
+               /* set to "tail" to put the response callback
+                * at the end of the callback list; this is required
+                * in case other overlays are present, so that the
+                * final entry is cached. */
+
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                                       "missing specifier for \"response-callback {head(default)|tail}\" "
+                                       "callback position\n", 0, 0, 0 );
+                       return 1;
+               }
+
+               if ( strcasecmp( argv[1], "head" ) == 0 ) {
+                       cm->response_cb = PCACHE_RESPONSE_CB_HEAD;
+
+               } else if ( strcasecmp( argv[1], "tail" ) == 0 ) {
+                       cm->response_cb = PCACHE_RESPONSE_CB_TAIL;
+
+               } else {
+                       Debug( LDAP_DEBUG_ANY,
+                                       "unknown specifier %s for \"response-callback {head(default)|tail}\" "
+                                       "callback position\n", argv[1], 0, 0 );
+                       return 1;
+               }
        }
        /* anything else */
        else {
-               return cm->db.bd_info->bi_db_config( &cm->db, fname, lineno, argc, argv );
+               rc = cm->db.bd_info->bi_db_config( &cm->db, fname, lineno, argc, argv );
        }
-       return 0;
+
+       if ( save_argv0 ) {
+               argv[0] = save_argv0;
+       }
+
+       return rc;
 }
 
 static int
@@ -1829,8 +1676,9 @@ proxy_cache_init(
        qm = (query_manager*)ch_malloc(sizeof(query_manager));
 
        cm->db = *be;
-       cm->db.be_flags |= SLAP_BFLAG_NO_SCHEMA_CHECK;
+       SLAP_DBFLAGS(&cm->db) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
        cm->db.be_private = NULL;
+       cm->db.be_pcl_mutexp = &cm->db.be_pcl_mutex;
        cm->qm = qm;
        cm->numattrsets = 0;
        cm->numtemplates = 0; 
@@ -1839,6 +1687,7 @@ proxy_cache_init(
        cm->max_entries = 0;
        cm->cur_entries = 0;
        cm->max_queries = 10000;
+       cm->response_cb = PCACHE_RESPONSE_CB_TAIL;
        cm->cc_period = 1000;
        cm->cc_paused = 0;
 
@@ -1862,18 +1711,43 @@ proxy_cache_open(
        BackendDB *be
 )
 {
-       slap_overinst *on = (slap_overinst *)be->bd_info;
-       cache_manager *cm = on->on_bi.bi_private;
-       int rc = 0;
+       slap_overinst   *on = (slap_overinst *)be->bd_info;
+       cache_manager   *cm = on->on_bi.bi_private;
+       int             rc = 0;
+       int             i;
 
-       if ( cm->db.bd_info->bi_db_open ) {
-               rc = cm->db.bd_info->bi_db_open( &cm->db );
+       /* consistency check (add more...) */
+       for ( i = 0; i < cm->numattrsets; i++ ) {
+               if ( cm->qm->attr_sets[i].attrs == NULL ) {
+                       fprintf( stderr, "proxy_cache_open(): "
+                               "attr set %d (of %d) missing\n",
+                               i, cm->numattrsets );
+                       return 1;
+               }
        }
 
-       ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
-       ldap_pvt_runqueue_insert( &syncrepl_rq, cm->cc_period,
-               consistency_check, on );
-       ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
+       rc = backend_startup_one( &cm->db );
+
+       /* There is no runqueue in TOOL mode */
+       if ( slapMode & SLAP_SERVER_MODE ) {
+               ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex );
+               ldap_pvt_runqueue_insert( &syncrepl_rq, cm->cc_period,
+                       consistency_check, on );
+               ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex );
+
+               /* Cached database must have the rootdn */
+               if ( BER_BVISNULL( &cm->db.be_rootndn )
+                               || BER_BVISEMPTY( &cm->db.be_rootndn ) )
+               {
+                       fprintf( stderr, "proxy_cache_open(): "
+                               "underlying database of type \"%s\"\n"
+                               "    serving naming context \"%s\"\n"
+                               "    has no \"rootdn\", required by \"proxycache\".\n",
+                               on->on_info->oi_orig->bi_type,
+                               cm->db.be_suffix[0].bv_val );
+                       return 1;
+               }
+       }
 
        return rc;
 }