]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/pcache.c
check for ee == NULL
[openldap] / servers / slapd / overlays / pcache.c
index 0e9b80df3025f0b5aa4b7c02778c19321000c4ea..70ef66ac5580ae1216e39db0ccfb35d90f3a82b7 100644 (file)
@@ -72,13 +72,14 @@ typedef struct cached_query_s {
        Qbase                                   *qbase;
        int                                             scope;
        struct berval                   q_uuid;         /* query identifier */
-       int                             q_sizelimit;
+       int                                             q_sizelimit;
        struct query_template_s         *qtemp; /* template of the query */
-       time_t                          expiry_time;    /* time till the query is considered valid */
+       time_t                                          expiry_time;    /* time till the query is considered valid */
        struct cached_query_s           *next;          /* next query in the template */
        struct cached_query_s           *prev;          /* previous query in the template */
-       struct cached_query_s           *lru_up;        /* previous query in the LRU list */
-       struct cached_query_s           *lru_down;      /* next query in the LRU list */
+       struct cached_query_s           *lru_up;        /* previous query in the LRU list */
+       struct cached_query_s           *lru_down;      /* next query in the LRU list */
+       ldap_pvt_thread_rdwr_t          rwlock;
 } CachedQuery;
 
 /*
@@ -156,7 +157,7 @@ struct query_manager_s;
 typedef CachedQuery *(QCfunc)(Operation *op, struct query_manager_s*,
        Query*, QueryTemplate*);
 typedef CachedQuery *(AddQueryfunc)(Operation *op, struct query_manager_s*,
-       Query*, QueryTemplate*, pc_caching_reason_t);
+       Query*, QueryTemplate*, pc_caching_reason_t, int wlock);
 typedef void (CRfunc)(struct query_manager_s*, struct berval*);
 
 /* LDAP query cache */
@@ -245,7 +246,8 @@ add_query(
        query_manager* qm,
        Query* query,
        QueryTemplate *templ,
-       pc_caching_reason_t why );
+       pc_caching_reason_t why,
+       int wlock);
 
 static int
 remove_query_data(
@@ -472,7 +474,7 @@ url2query(
                        goto error;
                }
 
-               cq = add_query( op, qm, &query, qt, PC_POSITIVE );
+               cq = add_query( op, qm, &query, qt, PC_POSITIVE, 0 );
                if ( cq != NULL ) {
                        cq->expiry_time = expiry_time;
                        cq->q_uuid = uuid;
@@ -1152,14 +1154,15 @@ free_query (CachedQuery* qc)
 }
 
 
-/* Add query to query cache */
+/* Add query to query cache, the returned Query is locked for writing */
 static CachedQuery *
 add_query(
        Operation *op,
        query_manager* qm,
        Query* query,
        QueryTemplate *templ,
-       pc_caching_reason_t why )
+       pc_caching_reason_t why,
+       int wlock)
 {
        CachedQuery* new_cached_query = (CachedQuery*) ch_malloc(sizeof(CachedQuery));
        Qbase *qbase, qb;
@@ -1198,6 +1201,10 @@ add_query(
        new_cached_query->scope = query->scope;
        new_cached_query->filter = query->filter;
        new_cached_query->first = first = filter_first( query->filter );
+       
+       ldap_pvt_thread_rdwr_init(&new_cached_query->rwlock);
+       if (wlock)
+               ldap_pvt_thread_rdwr_wlock(&new_cached_query->rwlock);
 
        qb.base = query->base;
 
@@ -1360,8 +1367,7 @@ remove_func (
        attr = attr_find( rs->sr_entry->e_attrs,  ad_queryId );
        if ( attr == NULL ) return 0;
 
-       for ( count = 0; !BER_BVISNULL( &attr->a_vals[count] ); count++ )
-               ;
+       count = attr->a_numvals;
        assert( count > 0 );
        qi = op->o_tmpalloc( sizeof( struct query_info ), op->o_tmpmemctx );
        qi->next = op->o_callback->sc_private;
@@ -1380,11 +1386,7 @@ remove_query_data(
 {
        struct query_info       *qi, *qnext;
        char                    filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
-#ifdef LDAP_COMP_MATCH
-       AttributeAssertion      ava = { NULL, BER_BVNULL, NULL };
-#else
-       AttributeAssertion      ava = { NULL, BER_BVNULL };
-#endif
+       AttributeAssertion      ava = ATTRIBUTEASSERTION_INIT;
        Filter                  filter = {LDAP_FILTER_EQUALITY};
        SlapReply               sreply = {REP_RESULT};
        slap_callback cb = { NULL, remove_func, NULL, NULL };
@@ -1447,6 +1449,7 @@ remove_query_data(
                        mod.sml_type = ad_queryId->ad_cname;
                        mod.sml_values = vals;
                        mod.sml_nvalues = NULL;
+                        mod.sml_numvals = 1;
                        mod.sml_next = NULL;
                        Debug( pcache_debug,
                                "REMOVING TEMP ATTR : TEMPLATE=%s\n",
@@ -1570,6 +1573,7 @@ struct search_info {
        int count;
        int slimit;
        int slimit_exceeded;
+       pc_caching_reason_t caching_reason;
        Entry *head, *tail;
 };
 
@@ -1665,11 +1669,7 @@ pcache_remove_entries_from_cache(
        SlapReply       rs = { REP_RESULT };
        Filter          f = { 0 };
        char            filtbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(entryUUID=)" ) ];
-#ifdef LDAP_COMP_MATCH
-       AttributeAssertion ava = { NULL, BER_BVNULL, NULL };
-#else
-       AttributeAssertion ava = { NULL, BER_BVNULL };
-#endif
+       AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
        AttributeName   attrs[ 2 ] = { 0 };
        int             s, rc;
 
@@ -1784,11 +1784,7 @@ pcache_remove_entry_queries_from_cache(
        SlapReply               rs = { REP_RESULT };
        Filter                  f = { 0 };
        char                    filter_str[ LDAP_LUTIL_UUIDSTR_BUFSIZE + STRLENOF( "(queryId=)" ) ];
-#ifdef LDAP_COMP_MATCH
-       AttributeAssertion      ava = { NULL, BER_BVNULL, NULL };
-#else
-       AttributeAssertion      ava = { NULL, BER_BVNULL };
-#endif
+       AttributeAssertion      ava = ATTRIBUTEASSERTION_INIT;
        AttributeName           attrs[ 2 ] = { 0 };
        int                     rc;
 
@@ -1917,46 +1913,18 @@ static int
 pcache_op_cleanup( Operation *op, SlapReply *rs ) {
        slap_callback   *cb = op->o_callback;
        struct search_info *si = cb->sc_private;
+       slap_overinst *on = si->on;
+       cache_manager *cm = on->on_bi.bi_private;
+       query_manager*          qm = cm->qm;
 
        if ( rs->sr_type == REP_SEARCH ) {
+               Entry *e;
+
                /* don't return more entries than requested by the client */
                if ( si->slimit && rs->sr_nentries >= si->slimit ) {
                        si->slimit_exceeded = 1;
                }
-       }
-
-       if ( rs->sr_type == REP_RESULT || 
-               op->o_abandon || 
-               rs->sr_err == SLAPD_ABANDON )
-       {
-               if ( si->save_attrs != NULL ) {
-                       rs->sr_attrs = si->save_attrs;
-                       op->ors_attrs = si->save_attrs;
-               }
-               op->o_callback = op->o_callback->sc_next;
-               op->o_tmpfree( cb, op->o_tmpmemctx );
-       }
-
-       return SLAP_CB_CONTINUE;
-}
-
-static int
-pcache_response(
-       Operation       *op,
-       SlapReply       *rs )
-{
-       struct search_info *si = op->o_callback->sc_private;
-       slap_overinst *on = si->on;
-       cache_manager *cm = on->on_bi.bi_private;
-       query_manager*          qm = cm->qm;
-
-       if ( si->save_attrs != NULL ) {
-               rs->sr_attrs = si->save_attrs;
-               op->ors_attrs = si->save_attrs;
-       }
 
-       if ( rs->sr_type == REP_SEARCH ) {
-               Entry *e;
                /* If we haven't exceeded the limit for this query,
                 * build a chain of answers to store. If we hit the
                 * limit, empty the chain and ignore the rest.
@@ -1981,36 +1949,34 @@ pcache_response(
                        }
                }
 
-               /* don't return more entries than requested by the client */
-               if ( si->slimit_exceeded ) {
-                       return 0;
-               }
-
-       } else if ( rs->sr_type == REP_RESULT ) {
-               pc_caching_reason_t why = PC_IGNORE;
-
-               if ( si->count ) {
-                       if ( rs->sr_err == LDAP_SUCCESS ) {
-                               why = PC_POSITIVE;
-
-                       } else if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED
-                               && si->qtemp->limitttl )
-                       {
-                               why = PC_SIZELIMIT;
-                       }
+       }
 
-               } else if ( si->qtemp->negttl && !si->count && !si->over &&
-                               rs->sr_err == LDAP_SUCCESS )
-               {
-                       why = PC_NEGATIVE;
+       if ( rs->sr_type == REP_RESULT || 
+               op->o_abandon || rs->sr_err == SLAPD_ABANDON )
+       {
+               if ( si->save_attrs != NULL ) {
+                       rs->sr_attrs = si->save_attrs;
+                       op->ors_attrs = si->save_attrs;
                }
-
-               if ( why != PC_IGNORE ) {
+               if ( op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
+                       filter_free( si->query.filter );
+                       if ( si->count ) {
+                               /* duplicate query, free it */
+                               Entry *e;
+                               for (;si->head; si->head=e) {
+                                       e = si->head->e_private;
+                                       si->head->e_private = NULL;
+                                       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, why );
+                               si->qtemp, si->caching_reason, 1 );
 
                        if ( qc != NULL ) {
-                               switch ( why ) {
+                               switch ( si->caching_reason ) {
                                case PC_POSITIVE:
                                        cache_entries( op, rs, &qc->q_uuid );
                                        break;
@@ -2019,6 +1985,7 @@ pcache_response(
                                        qc->q_sizelimit = rs->sr_nentries;
                                        break;
                                }
+                               ldap_pvt_thread_rdwr_wunlock(&qc->rwlock);
                                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                                cm->num_cached_queries++;
                                Debug( pcache_debug, "STORED QUERIES = %lu\n",
@@ -2050,6 +2017,47 @@ pcache_response(
                } else {
                        filter_free( si->query.filter );
                }
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+pcache_response(
+       Operation       *op,
+       SlapReply       *rs )
+{
+       struct search_info *si = op->o_callback->sc_private;
+
+       if ( si->save_attrs != NULL ) {
+               rs->sr_attrs = si->save_attrs;
+               op->ors_attrs = si->save_attrs;
+       }
+
+       if ( rs->sr_type == REP_SEARCH ) {
+               /* don't return more entries than requested by the client */
+               if ( si->slimit_exceeded ) {
+                       return 0;
+               }
+
+       } else if ( rs->sr_type == REP_RESULT ) {
+
+               if ( si->count ) {
+                       if ( rs->sr_err == LDAP_SUCCESS ) {
+                               si->caching_reason = PC_POSITIVE;
+
+                       } else if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED
+                               && si->qtemp->limitttl )
+                       {
+                               si->caching_reason = PC_SIZELIMIT;
+                       }
+
+               } else if ( si->qtemp->negttl && !si->count && !si->over &&
+                               rs->sr_err == LDAP_SUCCESS )
+               {
+                       si->caching_reason = PC_NEGATIVE;
+               }
+
 
                if ( si->slimit_exceeded ) {
                        rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
@@ -2293,6 +2301,7 @@ pcache_op_search(
 
                Debug( pcache_debug, "QUERY ANSWERABLE\n", 0, 0, 0 );
                op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
+               ldap_pvt_thread_rdwr_rlock(&answerable->rwlock);
                if ( BER_BVISNULL( &answerable->q_uuid )) {
                        /* No entries cached, just an empty result set */
                        i = rs->sr_err = 0;
@@ -2302,6 +2311,7 @@ pcache_op_search(
                        op->o_callback = NULL;
                        i = cm->db.bd_info->bi_op_search( op, rs );
                }
+               ldap_pvt_thread_rdwr_runlock(&answerable->rwlock);
                ldap_pvt_thread_rdwr_runlock(&qtemp->t_rwlock);
                op->o_bd = save_bd;
                op->o_callback = save_cb;
@@ -2347,6 +2357,7 @@ pcache_op_search(
                si->count = 0;
                si->slimit = 0;
                si->slimit_exceeded = 0;
+               si->caching_reason = PC_IGNORE;
                if ( op->ors_slimit && op->ors_slimit < cm->num_entries_limit ) {
                        si->slimit = op->ors_slimit;
                        op->ors_slimit = cm->num_entries_limit;
@@ -3192,11 +3203,7 @@ pcache_db_open(
                        SlapReply       rs = { 0 };
                        BerVarray       vals = NULL;
                        Filter          f = { 0 }, f2 = { 0 };
-#ifdef LDAP_COMP_MATCH
-                       AttributeAssertion      ava = { NULL, BER_BVNULL, NULL };
-#else
-                       AttributeAssertion      ava = { NULL, BER_BVNULL };
-#endif
+                       AttributeAssertion      ava = ATTRIBUTEASSERTION_INIT;
                        AttributeName   attrs[ 2 ] = { 0 };
 
                        connection_fake_init( &conn, &opbuf, thrctx );
@@ -3347,6 +3354,7 @@ 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",