X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Foverlays%2Fpcache.c;h=6875b19fa7a62a1cbc0ab2244e1cbd58083c947d;hb=ee3f05000055619ec6d4eee48b57fa5cb6085127;hp=9f97ca7bcbe81767c74044bfd7643447333ef115;hpb=6d7c1880a8bdfe44556743842c759b46aab35120;p=openldap diff --git a/servers/slapd/overlays/pcache.c b/servers/slapd/overlays/pcache.c index 9f97ca7bcb..6875b19fa7 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-2011 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; } @@ -2030,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; } @@ -2394,8 +2428,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: @@ -2596,10 +2632,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; } @@ -2864,6 +2910,7 @@ pcache_op_bind( if ( bi.bi_flags & BI_HASHED ) { BackendDB *be = op->o_bd; op->o_bd = &cm->db; + int delete = 0; Debug( pcache_debug, "pcache_op_bind: CACHED BIND for %s\n", op->o_req_dn.bv_val, 0, 0 ); @@ -2872,6 +2919,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; } @@ -2891,6 +2944,8 @@ pcache_op_bind( return SLAP_CB_CONTINUE; } +static slap_response refresh_merge; + static int pcache_op_search( Operation *op, @@ -2929,7 +2984,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 ) { @@ -2937,6 +2993,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; + } } } @@ -3005,15 +3065,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 ) { @@ -3036,7 +3098,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; @@ -3264,6 +3326,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; @@ -3271,7 +3334,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; @@ -3325,9 +3390,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=)" ) ]; @@ -3365,7 +3430,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; @@ -3388,17 +3453,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]; @@ -3416,7 +3481,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 ); @@ -3441,7 +3506,6 @@ consistency_check( OperationBuffer opbuf; Operation *op; - SlapReply rs = {REP_RESULT}; CachedQuery *query, *qprev; int return_val, pause = PCACHE_CC_PAUSED; QueryTemplate *templ; @@ -3487,7 +3551,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; } } @@ -3505,8 +3569,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); @@ -3528,7 +3592,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 @@ -3763,13 +3835,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 ); @@ -4025,7 +4107,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 ); @@ -4246,7 +4333,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; @@ -4719,6 +4806,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 ) { @@ -4726,6 +4814,7 @@ pcache_db_close( if ( query2url( op, qc, &bv, 0 ) == 0 ) { ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx ); + mod.sml_numvals++; } } } @@ -4752,7 +4841,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", @@ -4792,7 +4880,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 ); @@ -5522,7 +5622,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 ); }