X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fpcache.c;h=6971694282bcf848b42882deb94b1a581245157c;hb=c6b5abbfd20567116846ebc38f0005c429284c98;hp=b10320e4a627c30c94f4b4dd5497603aa552729f;hpb=1970251bb72d0a71da9375d94e9ef442a287f113;p=openldap diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index b10320e4a6..6971694282 100644 --- a/servers/slapd/overlays/pcache.c +++ b/servers/slapd/overlays/pcache.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2003-2009 The OpenLDAP Foundation. + * Copyright 2003-2012 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; @@ -346,7 +347,6 @@ add_query( static int remove_query_data( Operation *op, - SlapReply *rs, struct berval *query_uuid ); /* @@ -446,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; @@ -599,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; @@ -675,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; @@ -752,11 +754,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; @@ -865,6 +866,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; @@ -920,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 )) { @@ -992,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 ) { @@ -1001,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; } } } @@ -1017,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 */ @@ -1249,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 ) @@ -1260,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; @@ -1335,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; @@ -1384,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 ) @@ -1551,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 +1634,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 ); @@ -1608,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; } @@ -1746,7 +1785,6 @@ remove_func ( static int remove_query_data( Operation *op, - SlapReply *rs, struct berval *query_uuid ) { struct query_info *qi, *qnext; @@ -1757,8 +1795,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; @@ -1791,6 +1827,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", @@ -1969,7 +2006,6 @@ struct search_info { static void remove_query_and_data( Operation *op, - SlapReply *rs, cache_manager *cm, struct berval *uuid ) { @@ -1982,7 +2018,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); @@ -2032,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; } @@ -2055,7 +2087,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; @@ -2102,6 +2133,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 ); @@ -2120,7 +2152,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 ); @@ -2145,12 +2177,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; } @@ -2241,7 +2272,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 ); @@ -2257,7 +2288,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; @@ -2289,7 +2319,7 @@ 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, 0, query_uuid); @@ -2313,62 +2343,6 @@ pcache_op_cleanup( Operation *op, SlapReply *rs ) { 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 > 0 && rs->sr_nentries >= si->slimit ) { - si->slimit_exceeded = 1; - } - - /* 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. - */ - if ( !si->over ) { - /* check if the entry contains undefined - * attributes/objectClasses (ITS#5680) */ - if ( cm->check_cacheability && test_filter( op, rs->sr_entry, si->query.filter ) != LDAP_COMPARE_TRUE ) { - Debug( pcache_debug, "%s: query not cacheable because of schema issues in DN \"%s\"\n", - op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 ); - goto over; - } - - /* check for malformed entries: attrs with no values */ - { - Attribute *a = rs->sr_entry->e_attrs; - for (; a; a=a->a_next) { - if ( !a->a_numvals ) { - Debug( pcache_debug, "%s: query not cacheable because of attrs without values in DN \"%s\" (%s)\n", - op->o_log_prefix, rs->sr_entry->e_name.bv_val, - a->a_desc->ad_cname.bv_val ); - goto over; - } - } - } - - if ( si->count < si->max ) { - si->count++; - e = entry_dup( rs->sr_entry ); - if ( !si->head ) si->head = e; - if ( si->tail ) si->tail->e_private = e; - si->tail = e; - - } else { -over:; - si->over = 1; - si->count = 0; - for (;si->head; si->head=e) { - e = si->head->e_private; - si->head->e_private = NULL; - entry_free(si->head); - } - si->tail = NULL; - } - } - - } - if ( rs->sr_type == REP_RESULT || op->o_abandon || rs->sr_err == SLAPD_ABANDON ) { @@ -2389,8 +2363,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 ); @@ -2398,9 +2371,11 @@ over:; if ( qc != NULL ) { switch ( si->caching_reason ) { case PC_POSITIVE: - cache_entries( op, rs, &qc->q_uuid ); - if ( si->pbi ) + cache_entries( op, &qc->q_uuid ); + if ( si->pbi ) { + qc->bind_refcnt++; si->pbi->bi_cq = qc; + } break; case PC_SIZELIMIT: @@ -2446,6 +2421,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; @@ -2464,11 +2442,64 @@ pcache_response( } if ( rs->sr_type == REP_SEARCH ) { + Entry *e; + /* don't return more entries than requested by the client */ + if ( si->slimit > 0 && rs->sr_nentries >= si->slimit ) { + si->slimit_exceeded = 1; + } + + /* 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. + */ + if ( !si->over ) { + slap_overinst *on = si->on; + cache_manager *cm = on->on_bi.bi_private; + + /* check if the entry contains undefined + * attributes/objectClasses (ITS#5680) */ + if ( cm->check_cacheability && test_filter( op, rs->sr_entry, si->query.filter ) != LDAP_COMPARE_TRUE ) { + Debug( pcache_debug, "%s: query not cacheable because of schema issues in DN \"%s\"\n", + op->o_log_prefix, rs->sr_entry->e_name.bv_val, 0 ); + goto over; + } + + /* check for malformed entries: attrs with no values */ + { + Attribute *a = rs->sr_entry->e_attrs; + for (; a; a=a->a_next) { + if ( !a->a_numvals ) { + Debug( pcache_debug, "%s: query not cacheable because of attrs without values in DN \"%s\" (%s)\n", + op->o_log_prefix, rs->sr_entry->e_name.bv_val, + a->a_desc->ad_cname.bv_val ); + goto over; + } + } + } + + if ( si->count < si->max ) { + si->count++; + e = entry_dup( rs->sr_entry ); + if ( !si->head ) si->head = e; + if ( si->tail ) si->tail->e_private = e; + si->tail = e; + + } else { +over:; + si->over = 1; + si->count = 0; + for (;si->head; si->head=e) { + e = si->head->e_private; + si->head->e_private = NULL; + entry_free(si->head); + } + si->tail = NULL; + } + } if ( si->slimit_exceeded ) { return 0; } - } else if ( rs->sr_type == REP_RESULT ) { if ( si->count ) { @@ -2478,8 +2509,9 @@ pcache_response( } else if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED && si->qtemp->limitttl ) { - si->caching_reason = PC_SIZELIMIT; Entry *e; + + si->caching_reason = PC_SIZELIMIT; for (;si->head; si->head=e) { e = si->head->e_private; si->head->e_private = NULL; @@ -2597,10 +2629,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; } @@ -2611,7 +2653,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 ), @@ -2863,6 +2905,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; @@ -2873,6 +2916,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; } @@ -2892,6 +2941,8 @@ pcache_op_bind( return SLAP_CB_CONTINUE; } +static slap_response refresh_merge; + static int pcache_op_search( Operation *op, @@ -2930,7 +2981,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 ) { @@ -2938,6 +2990,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; + } } } @@ -3006,28 +3062,40 @@ 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 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); + 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; @@ -3109,19 +3177,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; } @@ -3142,6 +3221,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; @@ -3196,7 +3277,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; @@ -3243,6 +3323,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; @@ -3250,7 +3331,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; @@ -3304,9 +3387,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=)" ) ]; @@ -3335,6 +3418,7 @@ refresh_query( Operation *op, SlapReply *rs, CachedQuery *query, op->o_req_dn = query->qbase->base; op->o_req_ndn = query->qbase->base; op->ors_scope = query->scope; + op->ors_deref = LDAP_DEREF_NEVER; op->ors_slimit = SLAP_NO_LIMIT; op->ors_tlimit = SLAP_NO_LIMIT; op->ors_limit = NULL; @@ -3344,7 +3428,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; @@ -3367,17 +3451,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]; @@ -3395,7 +3479,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 ); @@ -3420,7 +3504,6 @@ consistency_check( OperationBuffer opbuf; Operation *op; - SlapReply rs = {REP_RESULT}; CachedQuery *query, *qprev; int return_val, pause = PCACHE_CC_PAUSED; QueryTemplate *templ; @@ -3466,7 +3549,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; } } @@ -3484,8 +3567,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); @@ -3494,7 +3577,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); @@ -3507,7 +3590,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 @@ -3742,13 +3833,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 ); @@ -4004,7 +4105,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 ); @@ -4225,7 +4331,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; @@ -4503,7 +4609,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; @@ -4568,8 +4674,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 ); @@ -4698,6 +4804,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 ) { @@ -4705,6 +4812,7 @@ pcache_db_close( if ( query2url( op, qc, &bv, 0 ) == 0 ) { ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx ); + mod.sml_numvals++; } } } @@ -4731,7 +4839,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", @@ -4771,7 +4878,19 @@ pcache_db_close( free( tm ); } - for ( i=0; inumattrsets; 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 ); @@ -5100,6 +5219,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 ) { @@ -5218,6 +5341,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 @@ -5383,7 +5520,6 @@ pcache_monitor_db_open( BackendDB *be ) int rc = 0; BackendInfo *mi; monitor_extra_t *mbe; - struct berval dummy = BER_BVC( "" ); if ( !SLAP_DBMONITORING( be ) ) { return 0; @@ -5443,7 +5579,7 @@ pcache_monitor_db_open( BackendDB *be ) rc = mbe->register_overlay( be, on, &cm->monitor_ndn ); if ( rc == 0 ) { rc = mbe->register_entry_attrs( &cm->monitor_ndn, a, cb, - &dummy, -1, &dummy); + NULL, -1, NULL); } cleanup:; @@ -5483,7 +5619,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 ); } @@ -5604,6 +5740,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;