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;
AttributeDescription **descs = NULL;
char *temp2;
- temp2 = ch_malloc( ftemp->bv_len );
+ temp2 = ch_malloc( ftemp->bv_len + 1 );
p1 = ftemp->bv_val;
t1 = temp2;
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 )) {
}
break;
}
- if ( !rc ) {
+ while ( !rc ) {
f1 = f1->f_next;
f2 = f2->f_next;
if ( f1 || 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;
}
}
}
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 */
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 )
int ret, rc, dir;
Avlnode *ptr;
CachedQuery cq, *qc;
+ fstack *stack = NULL, *fsp;
cq.filter = inputf;
cq.first = first;
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;
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 )
}
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);
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;
}
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:
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;
}
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 );
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;
}
return SLAP_CB_CONTINUE;
}
+static slap_response refresh_merge;
+
static int
pcache_op_search(
Operation *op,
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 ) {
pbi = cb->sc_private;
break;
}
+ if ( cb->sc_response == refresh_merge ) {
+ /* This is a refresh, do not search the cache */
+ return SLAP_CB_CONTINUE;
+ }
}
}
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 ) {
}
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;
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);
"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
attr_name->an_name.bv_val; attr_name++ )
{
bv.bv_len += attr_name->an_name.bv_len + 1;
- if ( attr_name->an_desc->ad_flags & SLAP_DESC_TEMPORARY ) {
+ if ( attr_name->an_desc &&
+ ( attr_name->an_desc->ad_flags & SLAP_DESC_TEMPORARY ) ) {
bv.bv_len += STRLENOF("undef:");
}
}
for ( attr_name = qm->attr_sets[i].attrs;
attr_name->an_name.bv_val; attr_name++ ) {
*ptr++ = ' ';
- if ( attr_name->an_desc->ad_flags & SLAP_DESC_TEMPORARY ) {
+ 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 );
i = 0;
while ((eq = strchr(eq, '=' ))) {
eq++;
- if ( eq[1] == ')' )
+ if ( eq[0] == ')' )
i++;
}
bv.bv_len = temp->bindftemp.bv_len + 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->ad_flags & SLAP_DESC_TEMPORARY ) {
+ 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 );
}
}