X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fpcache.c;h=6971694282bcf848b42882deb94b1a581245157c;hb=c6b5abbfd20567116846ebc38f0005c429284c98;hp=c5f2100f961ad621ea1eb15310336e24b9a8c770;hpb=f4a3304477e6d9a8488b111ebec4223d2fc378cf;p=openldap diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index c5f2100f96..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-2010 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; @@ -445,7 +446,7 @@ ftemp_attrs( struct berval *ftemp, struct berval *template, AttributeDescription **descs = NULL; char *temp2; - temp2 = ch_malloc( ftemp->bv_len ); + temp2 = ch_malloc( ftemp->bv_len + 1 ); p1 = ftemp->bv_val; t1 = temp2; @@ -598,7 +599,7 @@ url2query( LDAPURLDesc *lud = NULL; struct berval base, tempstr = BER_BVNULL, - uuid; + uuid = BER_BVNULL; int attrset; time_t expiry_time; time_t refresh_time; @@ -674,9 +675,11 @@ url2query( } ber_str2bv( &lud->lud_exts[ i ][ STRLENOF( "x-uuid=" ) ], 0, 0, &tmpUUID ); - rc = syn_UUID->ssyn_pretty( syn_UUID, &tmpUUID, &uuid, NULL ); - if ( rc != LDAP_SUCCESS ) { - goto error; + if ( !BER_BVISEMPTY( &tmpUUID ) ) { + rc = syn_UUID->ssyn_pretty( syn_UUID, &tmpUUID, &uuid, NULL ); + if ( rc != LDAP_SUCCESS ) { + goto error; + } } got |= GOT_UUID; @@ -919,38 +922,49 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 ) int rc, weight1, weight2; switch( f1->f_choice ) { - case LDAP_FILTER_PRESENT: + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: weight1 = 0; break; + case LDAP_FILTER_PRESENT: + weight1 = 1; + break; case LDAP_FILTER_EQUALITY: case LDAP_FILTER_GE: case LDAP_FILTER_LE: - weight1 = 1; + weight1 = 2; break; default: - weight1 = 2; + weight1 = 3; } switch( f2->f_choice ) { - case LDAP_FILTER_PRESENT: + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: weight2 = 0; break; + case LDAP_FILTER_PRESENT: + weight2 = 1; + break; case LDAP_FILTER_EQUALITY: case LDAP_FILTER_GE: case LDAP_FILTER_LE: - weight2 = 1; + weight2 = 2; break; default: - weight2 = 2; + weight2 = 3; } rc = weight1 - weight2; if ( !rc ) { switch( weight1 ) { case 0: + rc = pcache_filter_cmp( f1->f_and, f2->f_and ); break; case 1: - rc = lex_bvcmp( &f1->f_av_value, &f2->f_av_value ); break; case 2: + rc = lex_bvcmp( &f1->f_av_value, &f2->f_av_value ); + break; + case 3: if ( f1->f_choice == LDAP_FILTER_SUBSTRINGS ) { rc = 0; if ( !BER_BVISNULL( &f1->f_sub_initial )) { @@ -991,7 +1005,7 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 ) } break; } - if ( !rc ) { + while ( !rc ) { f1 = f1->f_next; f2 = f2->f_next; if ( f1 || f2 ) { @@ -1000,12 +1014,10 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 ) else if ( !f2 ) rc = 1; else { - while ( f1->f_choice == LDAP_FILTER_AND || f1->f_choice == LDAP_FILTER_OR ) - f1 = f1->f_and; - while ( f2->f_choice == LDAP_FILTER_AND || f2->f_choice == LDAP_FILTER_OR ) - f2 = f2->f_and; rc = pcache_filter_cmp( f1, f2 ); } + } else { + break; } } } @@ -1016,7 +1028,7 @@ static int pcache_filter_cmp( Filter *f1, Filter *f2 ) static int pcache_query_cmp( const void *v1, const void *v2 ) { const CachedQuery *q1 = v1, *q2 =v2; - return pcache_filter_cmp( q1->first, q2->first ); + return pcache_filter_cmp( q1->filter, q2->filter ); } /* add query on top of LRU list */ @@ -1248,6 +1260,11 @@ filter_first( Filter *f ) return f; } +typedef struct fstack { + struct fstack *fs_next; + Filter *fs_fs; + Filter *fs_fi; +} fstack; static CachedQuery * find_filter( Operation *op, Avlnode *root, Filter *inputf, Filter *first ) @@ -1259,6 +1276,7 @@ find_filter( Operation *op, Avlnode *root, Filter *inputf, Filter *first ) int ret, rc, dir; Avlnode *ptr; CachedQuery cq, *qc; + fstack *stack = NULL, *fsp; cq.filter = inputf; cq.first = first; @@ -1334,6 +1352,14 @@ nextpass: eqpass = 1; switch (fs->f_choice) { case LDAP_FILTER_OR: case LDAP_FILTER_AND: + if ( fs->f_next ) { + /* save our stack position */ + fsp = op->o_tmpalloc(sizeof(fstack), op->o_tmpmemctx); + fsp->fs_next = stack; + fsp->fs_fs = fs->f_next; + fsp->fs_fi = fi->f_next; + stack = fsp; + } fs = fs->f_and; fi = fi->f_and; res=1; @@ -1383,6 +1409,14 @@ nextpass: eqpass = 1; default: break; } + if (!fs && !fi && stack) { + /* pop the stack */ + fsp = stack; + stack = fsp->fs_next; + fs = fsp->fs_fs; + fi = fsp->fs_fi; + op->o_tmpfree(fsp, op->o_tmpmemctx); + } } while((res) && (fi != NULL) && (fs != NULL)); if ( res ) @@ -1550,7 +1584,9 @@ add_query( } new_cached_query->expiry_time = now + ttl; new_cached_query->refresh_time = ttr; + new_cached_query->bindref_time = 0; + new_cached_query->bind_refcnt = 0; new_cached_query->answerable_cnt = 0; new_cached_query->refcnt = 1; ldap_pvt_thread_mutex_init(&new_cached_query->answerable_cnt_mutex); @@ -1599,6 +1635,8 @@ add_query( templ->no_of_queries++; } else { ldap_pvt_thread_mutex_destroy(&new_cached_query->answerable_cnt_mutex); + if (wlock) + ldap_pvt_thread_rdwr_wunlock(&new_cached_query->rwlock); ldap_pvt_thread_rdwr_destroy( &new_cached_query->rwlock ); ch_free( new_cached_query ); new_cached_query = find_filter( op, qbase->scopes[query->scope], @@ -1609,16 +1647,16 @@ add_query( Debug( pcache_debug, "TEMPLATE %p QUERIES++ %d\n", (void *) templ, templ->no_of_queries, 0 ); - Debug( pcache_debug, "Unlock AQ index = %p \n", - (void *) templ, 0, 0 ); - ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock); - /* Adding on top of LRU list */ if ( rc == 0 ) { ldap_pvt_thread_mutex_lock(&qm->lru_mutex); add_query_on_top(qm, new_cached_query); ldap_pvt_thread_mutex_unlock(&qm->lru_mutex); } + Debug( pcache_debug, "Unlock AQ index = %p \n", + (void *) templ, 0, 0 ); + ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock); + return rc == 0 ? new_cached_query : NULL; } @@ -2305,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 ) { @@ -2390,8 +2372,10 @@ over:; switch ( si->caching_reason ) { case PC_POSITIVE: cache_entries( op, &qc->q_uuid ); - if ( si->pbi ) + if ( si->pbi ) { + qc->bind_refcnt++; si->pbi->bi_cq = qc; + } break; case PC_SIZELIMIT: @@ -2458,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 ) { @@ -2592,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; } @@ -2858,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; @@ -2868,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; } @@ -2887,6 +2941,8 @@ pcache_op_bind( return SLAP_CB_CONTINUE; } +static slap_response refresh_merge; + static int pcache_op_search( Operation *op, @@ -2925,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 ) { @@ -2933,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; + } } } @@ -3001,15 +3062,17 @@ pcache_op_search( answerable->answerable_cnt, 0, 0 ); ldap_pvt_thread_mutex_unlock( &answerable->answerable_cnt_mutex ); - ldap_pvt_thread_rdwr_rlock(&answerable->rwlock); + ldap_pvt_thread_rdwr_wlock(&answerable->rwlock); if ( BER_BVISNULL( &answerable->q_uuid )) { /* No entries cached, just an empty result set */ i = rs->sr_err = 0; send_ldap_result( op, rs ); } else { /* Let Bind know we used a cached query */ - if ( pbi ) + if ( pbi ) { + answerable->bind_refcnt++; pbi->bi_cq = answerable; + } op->o_bd = &cm->db; if ( cm->response_cb == PCACHE_RESPONSE_CB_TAIL ) { @@ -3032,7 +3095,7 @@ pcache_op_search( } i = cm->db.bd_info->bi_op_search( op, rs ); } - ldap_pvt_thread_rdwr_runlock(&answerable->rwlock); + ldap_pvt_thread_rdwr_wunlock(&answerable->rwlock); /* locked by qtemp->qcfunc (query_containment) */ ldap_pvt_thread_rdwr_runlock(&qtemp->t_rwlock); op->o_bd = save_bd; @@ -3355,6 +3418,7 @@ refresh_query( Operation *op, CachedQuery *query, slap_overinst *on ) 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; @@ -3503,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); @@ -3526,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 @@ -3761,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 ); @@ -4023,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 ); @@ -4244,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; @@ -4717,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 ) { @@ -4724,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++; } } } @@ -4750,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", @@ -4790,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 ); @@ -5420,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; @@ -5480,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:; @@ -5520,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 ); }