version 1.41, 2004/12/03 15:49:23
|
version 1.41.2.8, 2005/09/28 00:30:35
|
Line 1
|
Line 1
|
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/pcache.c,v 1.40 2004/11/26 23:57:38 hyc Exp $ */ |
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/pcache.c,v 1.59 2005/09/04 21:54:30 ando Exp $ */ |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
* |
* |
* Copyright 2003-2004 The OpenLDAP Foundation. |
* Copyright 2003-2005 The OpenLDAP Foundation. |
* Portions Copyright 2003 IBM Corporation. |
* Portions Copyright 2003 IBM Corporation. |
* Portions Copyright 2003 Symas Corporation. |
* Portions Copyright 2003 Symas Corporation. |
* All rights reserved. |
* All rights reserved. |
Line 32
|
Line 32
|
#include "lutil.h" |
#include "lutil.h" |
#include "ldap_rq.h" |
#include "ldap_rq.h" |
|
|
|
#include "config.h" |
|
|
/* query cache structs */ |
/* query cache structs */ |
/* query */ |
/* query */ |
|
|
Line 184 merge_entry(
|
Line 186 merge_entry(
|
op->o_tag = LDAP_REQ_MODIFY; |
op->o_tag = LDAP_REQ_MODIFY; |
op->orm_modlist = modlist; |
op->orm_modlist = modlist; |
op->o_bd->be_modify( op, &sreply ); |
op->o_bd->be_modify( op, &sreply ); |
slap_mods_free( modlist ); |
slap_mods_free( modlist, 1 ); |
} else if ( rc == LDAP_REFERRAL || |
} else if ( rc == LDAP_REFERRAL || |
rc == LDAP_NO_SUCH_OBJECT ) { |
rc == LDAP_NO_SUCH_OBJECT ) { |
syncrepl_add_glue( op, e ); |
syncrepl_add_glue( op, e ); |
Line 634 free_query (CachedQuery* qc)
|
Line 636 free_query (CachedQuery* qc)
|
free(qc->q_uuid.bv_val); |
free(qc->q_uuid.bv_val); |
filter_free(q->filter); |
filter_free(q->filter); |
free (q->base.bv_val); |
free (q->base.bv_val); |
for (i=0; q->attrs[i].an_name.bv_val; i++) { |
if ( q->attrs ) { |
free(q->attrs[i].an_name.bv_val); |
for (i=0; q->attrs[i].an_name.bv_val; i++) { |
|
free(q->attrs[i].an_name.bv_val); |
|
} |
|
free(q->attrs); |
} |
} |
free(q->attrs); |
|
free(qc); |
free(qc); |
} |
} |
|
|
Line 789 remove_query_data (
|
Line 793 remove_query_data (
|
{ |
{ |
struct query_info *qi, *qnext; |
struct query_info *qi, *qnext; |
char filter_str[64]; |
char filter_str[64]; |
AttributeAssertion ava; |
#ifdef LDAP_COMP_MATCH |
|
AttributeAssertion ava = { NULL, BER_BVNULL, NULL }; |
|
#else |
|
AttributeAssertion ava = { NULL, BER_BVNULL }; |
|
#endif |
Filter filter = {LDAP_FILTER_EQUALITY}; |
Filter filter = {LDAP_FILTER_EQUALITY}; |
SlapReply sreply = {REP_RESULT}; |
SlapReply sreply = {REP_RESULT}; |
slap_callback cb = { NULL, remove_func, NULL, NULL }; |
slap_callback cb = { NULL, remove_func, NULL, NULL }; |
Line 846 remove_query_data (
|
Line 854 remove_query_data (
|
vals[1].bv_val = NULL; |
vals[1].bv_val = NULL; |
vals[1].bv_len = 0; |
vals[1].bv_len = 0; |
mod.sml_op = LDAP_MOD_DELETE; |
mod.sml_op = LDAP_MOD_DELETE; |
|
mod.sml_flags = 0; |
mod.sml_desc = ad_queryid; |
mod.sml_desc = ad_queryid; |
mod.sml_type = ad_queryid->ad_cname; |
mod.sml_type = ad_queryid->ad_cname; |
mod.sml_values = vals; |
mod.sml_values = vals; |
Line 978 filter2template(
|
Line 987 filter2template(
|
|
|
(*filter_attrs)[*filter_cnt].an_desc = ad; |
(*filter_attrs)[*filter_cnt].an_desc = ad; |
(*filter_attrs)[*filter_cnt].an_name = ad->ad_cname; |
(*filter_attrs)[*filter_cnt].an_name = ad->ad_cname; |
(*filter_attrs)[*filter_cnt+1].an_name.bv_val = NULL; |
(*filter_attrs)[*filter_cnt].an_oc = NULL; |
(*filter_attrs)[*filter_cnt+1].an_name.bv_len = 0; |
(*filter_attrs)[*filter_cnt].an_oc_exclude = 0; |
|
BER_BVZERO( &(*filter_attrs)[*filter_cnt+1].an_name ); |
(*filter_cnt)++; |
(*filter_cnt)++; |
return 0; |
return 0; |
} |
} |
Line 1004 cache_entries(
|
Line 1014 cache_entries(
|
slap_overinst *on = si->on; |
slap_overinst *on = si->on; |
cache_manager *cm = on->on_bi.bi_private; |
cache_manager *cm = on->on_bi.bi_private; |
query_manager* qm = cm->qm; |
query_manager* qm = cm->qm; |
int i; |
|
int return_val = 0; |
int return_val = 0; |
Entry *e; |
Entry *e; |
struct berval crp_uuid; |
struct berval crp_uuid; |
Line 1160 add_filter_attrs(
|
Line 1169 add_filter_attrs(
|
*new_attrs = (AttributeName*)(op->o_tmpalloc((count+1)* |
*new_attrs = (AttributeName*)(op->o_tmpalloc((count+1)* |
sizeof(AttributeName), op->o_tmpmemctx)); |
sizeof(AttributeName), op->o_tmpmemctx)); |
if (attrs == NULL) { |
if (attrs == NULL) { |
(*new_attrs)[0].an_name.bv_val = "*"; |
BER_BVSTR( &(*new_attrs)[0].an_name, "*" ); |
(*new_attrs)[0].an_name.bv_len = 1; |
(*new_attrs)[0].an_desc = NULL; |
(*new_attrs)[1].an_name.bv_val = NULL; |
(*new_attrs)[0].an_oc = NULL; |
(*new_attrs)[1].an_name.bv_len = 0; |
(*new_attrs)[0].an_oc_exclude = 0; |
|
BER_BVZERO( &(*new_attrs)[1].an_name ); |
alluser = 1; |
alluser = 1; |
allop = 0; |
allop = 0; |
} else { |
} else { |
Line 1171 add_filter_attrs(
|
Line 1181 add_filter_attrs(
|
(*new_attrs)[i].an_name = attrs[i].an_name; |
(*new_attrs)[i].an_name = attrs[i].an_name; |
(*new_attrs)[i].an_desc = attrs[i].an_desc; |
(*new_attrs)[i].an_desc = attrs[i].an_desc; |
} |
} |
(*new_attrs)[count].an_name.bv_val = NULL; |
BER_BVZERO( &(*new_attrs)[count].an_name ); |
(*new_attrs)[count].an_name.bv_len = 0; |
|
alluser = an_find(*new_attrs, &AllUser); |
alluser = an_find(*new_attrs, &AllUser); |
allop = an_find(*new_attrs, &AllOper); |
allop = an_find(*new_attrs, &AllOper); |
} |
} |
Line 1189 add_filter_attrs(
|
Line 1198 add_filter_attrs(
|
(count+2)*sizeof(AttributeName), op->o_tmpmemctx)); |
(count+2)*sizeof(AttributeName), op->o_tmpmemctx)); |
(*new_attrs)[count].an_name = filter_attrs[i].an_name; |
(*new_attrs)[count].an_name = filter_attrs[i].an_name; |
(*new_attrs)[count].an_desc = filter_attrs[i].an_desc; |
(*new_attrs)[count].an_desc = filter_attrs[i].an_desc; |
|
(*new_attrs)[count].an_oc = NULL; |
|
(*new_attrs)[count].an_oc_exclude = 0; |
count++; |
count++; |
(*new_attrs)[count].an_name.bv_val = NULL; |
BER_BVZERO( &(*new_attrs)[count].an_name ); |
(*new_attrs)[count].an_name.bv_len = 0; |
|
} |
} |
} |
} |
|
|
|
/* NOTE: this is a quick workaround to let pcache minimally interact |
|
* with pagedResults. A more articulated solutions would be to |
|
* perform the remote query without control and cache all results, |
|
* performing the pagedResults search only within the client |
|
* and the proxy. This requires pcache to understand pagedResults. */ |
|
static int |
|
proxy_cache_chk_controls( |
|
Operation *op, |
|
SlapReply *rs ) |
|
{ |
|
const char *non = ""; |
|
const char *stripped = ""; |
|
|
|
switch( op->o_pagedresults ) { |
|
case SLAP_CONTROL_NONCRITICAL: |
|
non = "non-"; |
|
stripped = "; stripped"; |
|
/* fallthru */ |
|
|
|
case SLAP_CONTROL_CRITICAL: |
|
Debug( LDAP_DEBUG_ANY, "%s: " |
|
"%scritical pagedResults control " |
|
"disabled with proxy cache%s.\n", |
|
op->o_log_prefix, non, stripped ); |
|
|
|
slap_remove_control( op, rs, slap_cids.sc_pagedResults, NULL ); |
|
break; |
|
|
|
default: |
|
rs->sr_err = SLAP_CB_CONTINUE; |
|
break; |
|
} |
|
|
|
return rs->sr_err; |
|
} |
|
|
static int |
static int |
proxy_cache_search( |
proxy_cache_search( |
Operation *op, |
Operation *op, |
Line 1209 proxy_cache_search(
|
Line 1255 proxy_cache_search(
|
int i = -1; |
int i = -1; |
|
|
AttributeName *filter_attrs = NULL; |
AttributeName *filter_attrs = NULL; |
AttributeName *new_attrs = NULL; |
|
|
|
Query query; |
Query query; |
|
|
Line 1232 proxy_cache_search(
|
Line 1277 proxy_cache_search(
|
Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n", |
Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n", |
tempstr.bv_val, 0, 0 ); |
tempstr.bv_val, 0, 0 ); |
|
|
|
/* FIXME: cannot cache/answer requests with pagedResults control */ |
|
|
|
|
/* find attr set */ |
/* find attr set */ |
attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets); |
attr_set = get_attr_set(op->ors_attrs, qm, cm->numattrsets); |
|
|
Line 1306 proxy_cache_search(
|
Line 1354 proxy_cache_search(
|
for ( count = 0; !BER_BVISNULL( &op->ors_attrs[ count ].an_name ); count++ ) { |
for ( count = 0; !BER_BVISNULL( &op->ors_attrs[ count ].an_name ); count++ ) { |
ber_dupbv( &query.attrs[count].an_name, &op->ors_attrs[count].an_name ); |
ber_dupbv( &query.attrs[count].an_name, &op->ors_attrs[count].an_name ); |
query.attrs[count].an_desc = op->ors_attrs[count].an_desc; |
query.attrs[count].an_desc = op->ors_attrs[count].an_desc; |
|
query.attrs[count].an_oc = op->ors_attrs[count].an_oc; |
|
query.attrs[count].an_oc_exclude = op->ors_attrs[count].an_oc_exclude; |
} |
} |
if ( oc_attr_absent ) { |
if ( oc_attr_absent ) { |
query.attrs[ count ].an_desc = slap_schema.si_ad_objectClass; |
query.attrs[ count ].an_desc = slap_schema.si_ad_objectClass; |
ber_dupbv( &query.attrs[count].an_name, |
ber_dupbv( &query.attrs[count].an_name, |
&slap_schema.si_ad_objectClass->ad_cname ); |
&slap_schema.si_ad_objectClass->ad_cname ); |
|
query.attrs[ count ].an_oc = NULL; |
|
query.attrs[ count ].an_oc_exclude = 0; |
count++; |
count++; |
} |
} |
query.attrs[ count ].an_name.bv_val = NULL; |
BER_BVZERO( &query.attrs[ count ].an_name ); |
query.attrs[ count ].an_name.bv_len = 0; |
|
} |
} |
add_filter_attrs(op, &op->ors_attrs, query.attrs, filter_attrs); |
add_filter_attrs(op, &op->ors_attrs, query.attrs, filter_attrs); |
|
|
Line 1480 consistency_check(
|
Line 1531 consistency_check(
|
|
|
|
|
#define MAX_ATTR_SETS 500 |
#define MAX_ATTR_SETS 500 |
static void find_supersets( struct attr_set* attr_sets, int numsets ); |
|
static int compare_sets( struct attr_set* setA, int, int ); |
/* |
|
* compares two sets of attributes (indices i and j) |
|
* returns 0: if neither set is contained in the other set |
|
* 1: if set i is contained in set j |
|
* 2: if set j is contained in set i |
|
* 3: the sets are equivalent |
|
*/ |
|
|
static int |
static int |
proxy_cache_config( |
compare_sets(struct attr_set* set, int i, int j) |
BackendDB *be, |
|
const char *fname, |
|
int lineno, |
|
int argc, |
|
char **argv |
|
) |
|
{ |
{ |
slap_overinst *on = (slap_overinst *)be->bd_info; |
int k,l,numI,numJ; |
|
int common=0; |
|
int result=0; |
|
|
|
if (( set[i].attrs == NULL ) && ( set[j].attrs == NULL )) |
|
return 3; |
|
|
|
if ( set[i].attrs == NULL ) |
|
return 2; |
|
|
|
if ( set[j].attrs == NULL ) |
|
return 1; |
|
|
|
numI = set[i].count; |
|
numJ = set[j].count; |
|
|
|
for ( l=0; l < numI; l++ ) { |
|
for ( k = 0; k < numJ; k++ ) { |
|
if ( strcmp( set[i].attrs[l].an_name.bv_val, |
|
set[j].attrs[k].an_name.bv_val ) == 0 ) |
|
common++; |
|
} |
|
} |
|
|
|
if ( common == numI ) |
|
result = 1; |
|
|
|
if ( common == numJ ) |
|
result += 2; |
|
|
|
return result; |
|
} |
|
|
|
static void |
|
find_supersets ( struct attr_set* attr_sets, int numsets ) |
|
{ |
|
int num[MAX_ATTR_SETS]; |
|
int i, j, res; |
|
int* id_array; |
|
for ( i = 0; i < MAX_ATTR_SETS; i++ ) |
|
num[i] = 0; |
|
|
|
for ( i = 0; i < numsets; i++ ) { |
|
attr_sets[i].ID_array = (int*) ch_malloc( sizeof( int ) ); |
|
attr_sets[i].ID_array[0] = -1; |
|
} |
|
|
|
for ( i = 0; i < numsets; i++ ) { |
|
for ( j=i+1; j < numsets; j++ ) { |
|
res = compare_sets( attr_sets, i, j ); |
|
switch ( res ) { |
|
case 0: |
|
break; |
|
case 3: |
|
case 1: |
|
id_array = attr_sets[i].ID_array; |
|
attr_sets[i].ID_array = (int *) ch_realloc( id_array, |
|
( num[i] + 2 ) * sizeof( int )); |
|
attr_sets[i].ID_array[num[i]] = j; |
|
attr_sets[i].ID_array[num[i]+1] = -1; |
|
num[i]++; |
|
if (res == 1) |
|
break; |
|
case 2: |
|
id_array = attr_sets[j].ID_array; |
|
attr_sets[j].ID_array = (int *) ch_realloc( id_array, |
|
( num[j] + 2 ) * sizeof( int )); |
|
attr_sets[j].ID_array[num[j]] = i; |
|
attr_sets[j].ID_array[num[j]+1] = -1; |
|
num[j]++; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
enum { |
|
PC_MAIN = 1, |
|
PC_ATTR, |
|
PC_TEMP, |
|
PC_RESP |
|
}; |
|
|
|
static ConfigDriver pc_cf_gen; |
|
static ConfigLDAPadd pc_ldadd; |
|
static ConfigCfAdd pc_cfadd; |
|
|
|
static ConfigTable pccfg[] = { |
|
{ "proxycache", "backend> <max_entries> <numattrsets> <entry limit> " |
|
"<cycle_time", |
|
6, 6, 0, ARG_MAGIC|ARG_NO_DELETE|PC_MAIN, pc_cf_gen, |
|
"( OLcfgOvAt:2.1 NAME 'olcProxyCache' " |
|
"DESC 'ProxyCache basic parameters' " |
|
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, |
|
{ "proxyattrset", "index> <attributes...", |
|
2, 0, 0, ARG_MAGIC|PC_ATTR, pc_cf_gen, |
|
"( OLcfgOvAt:2.2 NAME 'olcProxyAttrset' " |
|
"DESC 'A set of attributes to cache' " |
|
"SYNTAX OMsDirectoryString )", NULL, NULL }, |
|
{ "proxytemplate", "filter> <attrset-index> <TTL", |
|
4, 4, 0, ARG_MAGIC|PC_TEMP, pc_cf_gen, |
|
"( OLcfgOvAt:2.3 NAME 'olcProxyTemplate' " |
|
"DESC 'Filter template, attrset, and cache TTL' " |
|
"SYNTAX OMsDirectoryString )", NULL, NULL }, |
|
{ "response-callback", "head|tail(default)", |
|
2, 2, 0, ARG_MAGIC|PC_RESP, pc_cf_gen, |
|
"( OLcfgOvAt:2.4 NAME 'olcProxyResponseCB' " |
|
"DESC 'Response callback position in overlay stack' " |
|
"SYNTAX OMsDirectoryString )", NULL, NULL }, |
|
{ NULL, NULL, 0, 0, 0, ARG_IGNORED } |
|
}; |
|
|
|
static ConfigOCs pcocs[] = { |
|
{ "( OLcfgOvOc:2.1 " |
|
"NAME 'olcPcacheConfig' " |
|
"DESC 'ProxyCache configuration' " |
|
"SUP olcOverlayConfig " |
|
"MUST ( olcProxyCache $ olcProxyAttrset $ olcProxyTemplate ) " |
|
"MAY olcProxyResponseCB )", Cft_Overlay, pccfg, NULL, pc_cfadd }, |
|
{ "( OLcfgOvOc:2.2 " |
|
"NAME 'olcPcacheDatabase' " |
|
"DESC 'Cache database configuration' " |
|
"AUXILIARY )", Cft_Misc, pccfg, pc_ldadd }, |
|
{ NULL, 0, NULL } |
|
}; |
|
|
|
static int |
|
pc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca ) |
|
{ |
|
slap_overinst *on; |
|
cache_manager *cm; |
|
|
|
if ( p->ce_type != Cft_Overlay || !p->ce_bi || |
|
p->ce_bi->bi_cf_ocs != pcocs ) |
|
return LDAP_CONSTRAINT_VIOLATION; |
|
|
|
on = (slap_overinst *)p->ce_bi; |
|
cm = on->on_bi.bi_private; |
|
ca->be = &cm->db; |
|
return LDAP_SUCCESS; |
|
} |
|
|
|
static int |
|
pc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) |
|
{ |
|
CfEntryInfo *pe = p->e_private; |
|
slap_overinst *on = (slap_overinst *)pe->ce_bi; |
|
cache_manager *cm = on->on_bi.bi_private; |
|
struct berval bv; |
|
|
|
/* FIXME: should not hardcode "olcDatabase" here */ |
|
bv.bv_len = sprintf( ca->msg, "olcDatabase=%s", cm->db.bd_info->bi_type ); |
|
bv.bv_val = ca->msg; |
|
ca->be = &cm->db; |
|
|
|
/* We can only create this entry if the database is table-driven |
|
*/ |
|
if ( cm->db.bd_info->bi_cf_ocs ) |
|
config_build_entry( op, rs, pe, ca, &bv, cm->db.bd_info->bi_cf_ocs, |
|
&pcocs[1] ); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
pc_cf_gen( ConfigArgs *c ) |
|
{ |
|
slap_overinst *on = (slap_overinst *)c->bi; |
cache_manager* cm = on->on_bi.bi_private; |
cache_manager* cm = on->on_bi.bi_private; |
query_manager* qm = cm->qm; |
query_manager* qm = cm->qm; |
QueryTemplate* temp; |
QueryTemplate* temp; |
AttributeName* attr_name; |
AttributeName* attr_name; |
AttributeName* attrarray; |
AttributeName* attrarray; |
const char* text=NULL; |
const char* text=NULL; |
char *save_argv0 = NULL; |
int i, num, rc = 0; |
|
char *ptr; |
|
|
int index, i; |
if ( c->op == SLAP_CONFIG_EMIT ) { |
int num; |
struct berval bv; |
int rc = 0; |
switch( c->type ) { |
|
case PC_MAIN: |
if ( strncasecmp( argv[0], "proxycache-", STRLENOF( "proxycache-" ) ) == 0 ) { |
bv.bv_len = sprintf( c->msg, "%s %d %d %d %d", |
save_argv0 = argv[0]; |
cm->db.bd_info->bi_type, cm->max_entries, cm->numattrsets, |
argv[0] += STRLENOF( "proxycache-" ); |
cm->num_entries_limit, cm->cc_period ); |
|
bv.bv_val = c->msg; |
|
value_add_one( &c->rvalue_vals, &bv ); |
|
break; |
|
case PC_ATTR: |
|
for (i=0; i<cm->numattrsets; i++) { |
|
if ( !qm->attr_sets[i].count ) continue; |
|
|
|
bv.bv_len = sprintf( c->msg, "%d", i ); |
|
|
|
/* 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; |
|
|
|
bv.bv_val = ch_malloc( bv.bv_len+1 ); |
|
ptr = lutil_strcopy( bv.bv_val, c->msg ); |
|
for ( attr_name = qm->attr_sets[i].attrs; |
|
attr_name->an_name.bv_val; attr_name++ ) { |
|
*ptr++ = ' '; |
|
ptr = lutil_strcopy( ptr, attr_name->an_name.bv_val ); |
|
} |
|
ber_bvarray_add( &c->rvalue_vals, &bv ); |
|
} |
|
if ( !c->rvalue_vals ) |
|
rc = 1; |
|
break; |
|
case PC_TEMP: |
|
for (i=0; i<cm->numtemplates; i++) { |
|
bv.bv_len = sprintf( c->msg, " %d %ld", |
|
qm->templates[i].attr_set_index, |
|
qm->templates[i].ttl ); |
|
bv.bv_len += qm->templates[i].querystr.bv_len + 2; |
|
bv.bv_val = ch_malloc( bv.bv_len+1 ); |
|
ptr = bv.bv_val; |
|
*ptr++ = '"'; |
|
ptr = lutil_strcopy( ptr, qm->templates[i].querystr.bv_val ); |
|
*ptr++ = '"'; |
|
strcpy( ptr, c->msg ); |
|
ber_bvarray_add( &c->rvalue_vals, &bv ); |
|
} |
|
if ( !c->rvalue_vals ) |
|
rc = 1; |
|
break; |
|
case PC_RESP: |
|
if ( cm->response_cb == PCACHE_RESPONSE_CB_HEAD ) { |
|
BER_BVSTR( &bv, "head" ); |
|
} else { |
|
BER_BVSTR( &bv, "tail" ); |
|
} |
|
value_add_one( &c->rvalue_vals, &bv ); |
|
break; |
|
} |
|
return rc; |
|
} else if ( c->op == LDAP_MOD_DELETE ) { |
|
return 1; /* FIXME */ |
|
#if 0 |
|
switch( c->type ) { |
|
case PC_ATTR: |
|
case PC_TEMP: |
|
} |
|
return rc; |
|
#endif |
} |
} |
|
|
if ( strcasecmp( argv[0], "proxycache" ) == 0 ) { |
switch( c->type ) { |
if ( argc < 6 ) { |
case PC_MAIN: |
fprintf( stderr, "%s: line %d: missing arguments in \"proxycache" |
cm->numattrsets = atoi( c->argv[3] ); |
" <backend> <max_entries> <numattrsets> <entry limit> " |
if ( cm->numattrsets > MAX_ATTR_SETS ) { |
"<cycle_time>\"\n", fname, lineno ); |
sprintf( c->msg, "numattrsets must be <= %d", MAX_ATTR_SETS ); |
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
return( 1 ); |
return( 1 ); |
} |
} |
|
cm->db.bd_info = backend_info( c->argv[1] ); |
cm->db.bd_info = backend_info( argv[1] ); |
|
if ( !cm->db.bd_info ) { |
if ( !cm->db.bd_info ) { |
fprintf( stderr, "%s: line %d: backend %s unknown\n", |
sprintf( c->msg, "unknown backend type" ); |
fname, lineno, argv[1] ); |
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
|
return( 1 ); |
|
} |
|
if ( cm->db.bd_info->bi_db_init( &cm->db ) ) { |
|
sprintf( c->msg, "backend %s init failed", c->argv[1] ); |
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
return( 1 ); |
return( 1 ); |
} |
} |
if ( cm->db.bd_info->bi_db_init( &cm->db ) ) return( 1 ); |
|
|
|
/* This type is in use, needs to be opened */ |
/* This type is in use, needs to be opened */ |
cm->db.bd_info->bi_nDB++; |
cm->db.bd_info->bi_nDB++; |
|
|
cm->max_entries = atoi( argv[2] ); |
cm->max_entries = atoi( c->argv[2] ); |
|
|
cm->numattrsets = atoi( argv[3] ); |
cm->num_entries_limit = atoi( c->argv[4] ); |
if ( cm->numattrsets > MAX_ATTR_SETS ) { |
cm->cc_period = atoi( c->argv[5] ); |
fprintf( stderr, "%s: line %d: numattrsets must be <= %d\n", |
Debug( LDAP_DEBUG_TRACE, |
fname, lineno, MAX_ATTR_SETS ); |
|
return( 1 ); |
|
} |
|
|
|
cm->num_entries_limit = atoi( argv[4] ); |
|
cm->cc_period = atoi( argv[5] ); |
|
Debug( LDAP_DEBUG_ANY, |
|
"Total # of attribute sets to be cached = %d\n", |
"Total # of attribute sets to be cached = %d\n", |
cm->numattrsets, 0, 0 ); |
cm->numattrsets, 0, 0 ); |
qm->attr_sets = ( struct attr_set * )ch_malloc( cm->numattrsets * |
qm->attr_sets = ( struct attr_set * )ch_malloc( cm->numattrsets * |
Line 1548 proxy_cache_config(
|
Line 1826 proxy_cache_config(
|
for ( i = 0; i < cm->numattrsets; i++ ) { |
for ( i = 0; i < cm->numattrsets; i++ ) { |
qm->attr_sets[i].attrs = NULL; |
qm->attr_sets[i].attrs = NULL; |
} |
} |
|
break; |
} else if ( strcasecmp( argv[0], "proxyattrset" ) == 0 ) { |
case PC_ATTR: |
if ( argc < 3 ) { |
num = atoi( c->argv[1] ); |
fprintf( stderr, "%s: line %d: missing arguments in \"proxyattrset " |
if (num >= cm->numattrsets) { |
"<index> <attributes>\"\n", fname, lineno ); |
sprintf( c->msg, "attrset index out of bounds" ); |
return( 1 ); |
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
} |
|
Debug( LDAP_DEBUG_ANY, "Attribute Set # %d\n", |
|
atoi( argv[1] ), 0, 0 ); |
|
if (atoi(argv[1]) >= cm->numattrsets) { |
|
fprintf( stderr, "%s; line %d index out of bounds \n", |
|
fname, lineno ); |
|
return 1; |
return 1; |
} |
} |
index = atoi( argv[1] ); |
if ( c->argv[2] && strcmp( c->argv[2], "*" ) ) { |
if ( argv[2] && strcmp( argv[2], "*" ) ) { |
qm->attr_sets[num].count = c->argc - 2; |
qm->attr_sets[index].count = argc - 2; |
qm->attr_sets[num].attrs = (AttributeName*)ch_malloc( |
qm->attr_sets[index].attrs = (AttributeName*)ch_malloc( |
(c->argc-1) * sizeof( AttributeName )); |
(argc-1) * sizeof( AttributeName )); |
attr_name = qm->attr_sets[num].attrs; |
attr_name = qm->attr_sets[index].attrs; |
for ( i = 2; i < c->argc; i++ ) { |
for ( i = 2; i < argc; i++ ) { |
ber_str2bv( c->argv[i], 0, 1, &attr_name->an_name); |
Debug( LDAP_DEBUG_ANY, "\t %s\n", |
|
argv[i], 0, 0 ); |
|
ber_str2bv( argv[i], 0, 1, |
|
&attr_name->an_name); |
|
attr_name->an_desc = NULL; |
attr_name->an_desc = NULL; |
slap_bv2ad( &attr_name->an_name, |
if ( slap_bv2ad( &attr_name->an_name, |
&attr_name->an_desc, &text ); |
&attr_name->an_desc, &text )) { |
|
strcpy( c->msg, text ); |
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
|
ch_free( qm->attr_sets[num].attrs ); |
|
qm->attr_sets[num].attrs = NULL; |
|
qm->attr_sets[num].count = 0; |
|
return 1; |
|
} |
|
attr_name->an_oc = NULL; |
|
attr_name->an_oc_exclude = 0; |
attr_name++; |
attr_name++; |
attr_name->an_name.bv_val = NULL; |
BER_BVZERO( &attr_name->an_name ); |
attr_name->an_name.bv_len = 0; |
|
} |
} |
} |
} |
} else if ( strcasecmp( argv[0], "proxytemplate" ) == 0 ) { |
break; |
if ( argc != 4 ) { |
case PC_TEMP: |
fprintf( stderr, "%s: line %d: missing argument(s) in " |
if (( i = atoi( c->argv[2] )) >= cm->numattrsets ) { |
"\"proxytemplate <filter> <proj attr set> <TTL>\" line\n", |
sprintf( c->msg, "template index invalid" ); |
fname, lineno ); |
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
return( 1 ); |
|
} |
|
if (( i = atoi( argv[2] )) >= cm->numattrsets ) { |
|
Debug( LDAP_DEBUG_ANY, |
|
"%s: line %d, template index invalid\n", |
|
fname, lineno, 0 ); |
|
return 1; |
return 1; |
} |
} |
num = cm->numtemplates; |
num = cm->numtemplates; |
Line 1602 proxy_cache_config(
|
Line 1872 proxy_cache_config(
|
temp = qm->templates + num; |
temp = qm->templates + num; |
ldap_pvt_thread_rdwr_init( &temp->t_rwlock ); |
ldap_pvt_thread_rdwr_init( &temp->t_rwlock ); |
temp->query = temp->query_last = NULL; |
temp->query = temp->query_last = NULL; |
temp->ttl = atoi( argv[3] ); |
temp->ttl = atoi( c->argv[3] ); |
temp->no_of_queries = 0; |
temp->no_of_queries = 0; |
if ( argv[1] == NULL ) { |
|
Debug( LDAP_DEBUG_ANY, |
ber_str2bv( c->argv[1], 0, 1, &temp->querystr ); |
"Templates string not specified " |
Debug( LDAP_DEBUG_TRACE, "Template:\n", 0, 0, 0 ); |
"for template %d\n", num, 0, 0 ); |
Debug( LDAP_DEBUG_TRACE, " query template: %s\n", |
return 1; |
|
} |
|
ber_str2bv( argv[1], 0, 1, &temp->querystr ); |
|
Debug( LDAP_DEBUG_ANY, "Template:\n", 0, 0, 0 ); |
|
Debug( LDAP_DEBUG_ANY, " query template: %s\n", |
|
temp->querystr.bv_val, 0, 0 ); |
temp->querystr.bv_val, 0, 0 ); |
temp->attr_set_index = i; |
temp->attr_set_index = i; |
Debug( LDAP_DEBUG_ANY, " attributes: \n", 0, 0, 0 ); |
Debug( LDAP_DEBUG_TRACE, " attributes: \n", 0, 0, 0 ); |
if ( ( attrarray = qm->attr_sets[i].attrs ) != NULL ) { |
if ( ( attrarray = qm->attr_sets[i].attrs ) != NULL ) { |
for ( i=0; attrarray[i].an_name.bv_val; i++ ) |
for ( i=0; attrarray[i].an_name.bv_val; i++ ) |
Debug( LDAP_DEBUG_ANY, "\t%s\n", |
Debug( LDAP_DEBUG_TRACE, "\t%s\n", |
attrarray[i].an_name.bv_val, 0, 0 ); |
attrarray[i].an_name.bv_val, 0, 0 ); |
} |
} |
temp++; |
temp++; |
temp->querystr.bv_val = NULL; |
temp->querystr.bv_val = NULL; |
cm->numtemplates++; |
cm->numtemplates++; |
|
break; |
} else if ( strcasecmp( argv[0], "response-callback" ) == 0 ) { |
case PC_RESP: |
/* set to "tail" to put the response callback |
if ( strcasecmp( c->argv[1], "head" ) == 0 ) { |
* at the end of the callback list; this is required |
|
* in case other overlays are present, so that the |
|
* final entry is cached. */ |
|
|
|
if ( argc < 2 ) { |
|
Debug( LDAP_DEBUG_ANY, |
|
"missing specifier for \"response-callback {head(default)|tail}\" " |
|
"callback position\n", 0, 0, 0 ); |
|
return 1; |
|
} |
|
|
|
if ( strcasecmp( argv[1], "head" ) == 0 ) { |
|
cm->response_cb = PCACHE_RESPONSE_CB_HEAD; |
cm->response_cb = PCACHE_RESPONSE_CB_HEAD; |
|
|
} else if ( strcasecmp( argv[1], "tail" ) == 0 ) { |
} else if ( strcasecmp( c->argv[1], "tail" ) == 0 ) { |
cm->response_cb = PCACHE_RESPONSE_CB_TAIL; |
cm->response_cb = PCACHE_RESPONSE_CB_TAIL; |
|
|
} else { |
} else { |
Debug( LDAP_DEBUG_ANY, |
sprintf( c->msg, "unknown specifier" ); |
"unknown specifier %s for \"response-callback {head(default)|tail}\" " |
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->msg, 0 ); |
"callback position\n", argv[1], 0, 0 ); |
|
return 1; |
return 1; |
} |
} |
|
break; |
} |
} |
/* anything else */ |
return rc; |
else { |
} |
rc = cm->db.bd_info->bi_db_config( &cm->db, fname, lineno, argc, argv ); |
|
} |
|
|
|
if ( save_argv0 ) { |
static int |
argv[0] = save_argv0; |
proxy_cache_config( |
} |
BackendDB *be, |
|
const char *fname, |
|
int lineno, |
|
int argc, |
|
char **argv |
|
) |
|
{ |
|
slap_overinst *on = (slap_overinst *)be->bd_info; |
|
cache_manager* cm = on->on_bi.bi_private; |
|
|
return rc; |
/* Something for the cache database? */ |
|
if ( cm->db.bd_info && cm->db.bd_info->bi_db_config ) |
|
return cm->db.bd_info->bi_db_config( &cm->db, fname, lineno, |
|
argc, argv ); |
|
return SLAP_CONF_UNKNOWN; |
} |
} |
|
|
static int |
static int |
Line 1716 proxy_cache_open(
|
Line 1979 proxy_cache_open(
|
slap_overinst *on = (slap_overinst *)be->bd_info; |
slap_overinst *on = (slap_overinst *)be->bd_info; |
cache_manager *cm = on->on_bi.bi_private; |
cache_manager *cm = on->on_bi.bi_private; |
int rc = 0; |
int rc = 0; |
int i; |
|
|
|
/* consistency check (add more...) */ |
|
for ( i = 0; i < cm->numattrsets; i++ ) { |
|
if ( cm->qm->attr_sets[i].attrs == NULL ) { |
|
fprintf( stderr, "proxy_cache_open(): " |
|
"attr set %d (of %d) missing\n", |
|
i, cm->numattrsets ); |
|
return 1; |
|
} |
|
} |
|
|
|
/* need to inherit something from the original database... */ |
/* need to inherit something from the original database... */ |
cm->db.be_def_limit = be->be_def_limit; |
cm->db.be_def_limit = be->be_def_limit; |
Line 1740 proxy_cache_open(
|
Line 1992 proxy_cache_open(
|
if ( slapMode & SLAP_SERVER_MODE ) { |
if ( slapMode & SLAP_SERVER_MODE ) { |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
ldap_pvt_runqueue_insert( &slapd_rq, cm->cc_period, |
ldap_pvt_runqueue_insert( &slapd_rq, cm->cc_period, |
consistency_check, on ); |
consistency_check, on, |
|
"pcache_consistency", be->be_suffix[0].bv_val ); |
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
|
/* Cached database must have the rootdn */ |
/* Cached database must have the rootdn */ |
if ( BER_BVISNULL( &cm->db.be_rootndn ) |
if ( BER_BVISNULL( &cm->db.be_rootndn ) |
|| BER_BVISEMPTY( &cm->db.be_rootndn ) ) |
|| BER_BVISEMPTY( &cm->db.be_rootndn ) ) |
{ |
{ |
fprintf( stderr, "proxy_cache_open(): " |
Debug( LDAP_DEBUG_ANY, "proxy_cache_open(): " |
"underlying database of type \"%s\"\n" |
"underlying database of type \"%s\"\n" |
" serving naming context \"%s\"\n" |
" serving naming context \"%s\"\n" |
" has no \"rootdn\", required by \"proxycache\".\n", |
" has no \"rootdn\", required by \"proxycache\".\n", |
on->on_info->oi_orig->bi_type, |
on->on_info->oi_orig->bi_type, |
cm->db.be_suffix[0].bv_val ); |
cm->db.be_suffix[0].bv_val, 0 ); |
return 1; |
return 1; |
} |
} |
} |
} |
Line 1810 proxy_cache_destroy(
|
Line 2063 proxy_cache_destroy(
|
slap_overinst *on = (slap_overinst *)be->bd_info; |
slap_overinst *on = (slap_overinst *)be->bd_info; |
cache_manager *cm = on->on_bi.bi_private; |
cache_manager *cm = on->on_bi.bi_private; |
query_manager *qm = cm->qm; |
query_manager *qm = cm->qm; |
int rc = 0; |
|
|
|
if ( cm->db.bd_info->bi_db_destroy ) { |
/* cleanup stuff inherited from the original database... */ |
rc = cm->db.bd_info->bi_db_destroy( &cm->db ); |
cm->db.be_suffix = NULL; |
} |
cm->db.be_nsuffix = NULL; |
ldap_pvt_thread_mutex_destroy(&qm->lru_mutex); |
BER_BVZERO( &cm->db.be_rootdn ); |
ldap_pvt_thread_mutex_destroy(&cm->cache_mutex); |
BER_BVZERO( &cm->db.be_rootndn ); |
ldap_pvt_thread_mutex_destroy(&cm->remove_mutex); |
BER_BVZERO( &cm->db.be_rootpw ); |
|
/* FIXME: there might be more... */ |
|
|
|
backend_destroy_one( &cm->db, 0 ); |
|
|
|
ldap_pvt_thread_mutex_destroy( &qm->lru_mutex ); |
|
ldap_pvt_thread_mutex_destroy( &cm->cache_mutex ); |
|
ldap_pvt_thread_mutex_destroy( &cm->remove_mutex ); |
free( qm ); |
free( qm ); |
free( cm ); |
free( cm ); |
return rc; |
|
} |
|
|
|
static void |
|
find_supersets ( struct attr_set* attr_sets, int numsets ) |
|
{ |
|
int num[MAX_ATTR_SETS]; |
|
int i, j, res; |
|
int* id_array; |
|
for ( i = 0; i < MAX_ATTR_SETS; i++ ) |
|
num[i] = 0; |
|
|
|
for ( i = 0; i < numsets; i++ ) { |
return 0; |
attr_sets[i].ID_array = (int*) ch_malloc( sizeof( int ) ); |
|
attr_sets[i].ID_array[0] = -1; |
|
} |
|
|
|
for ( i = 0; i < numsets; i++ ) { |
|
for ( j=i+1; j < numsets; j++ ) { |
|
res = compare_sets( attr_sets, i, j ); |
|
switch ( res ) { |
|
case 0: |
|
break; |
|
case 3: |
|
case 1: |
|
id_array = attr_sets[i].ID_array; |
|
attr_sets[i].ID_array = (int *) ch_realloc( id_array, |
|
( num[i] + 2 ) * sizeof( int )); |
|
attr_sets[i].ID_array[num[i]] = j; |
|
attr_sets[i].ID_array[num[i]+1] = -1; |
|
num[i]++; |
|
if (res == 1) |
|
break; |
|
case 2: |
|
id_array = attr_sets[j].ID_array; |
|
attr_sets[j].ID_array = (int *) ch_realloc( id_array, |
|
( num[j] + 2 ) * sizeof( int )); |
|
attr_sets[j].ID_array[num[j]] = i; |
|
attr_sets[j].ID_array[num[j]+1] = -1; |
|
num[j]++; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* compares two sets of attributes (indices i and j) |
|
* returns 0: if neither set is contained in the other set |
|
* 1: if set i is contained in set j |
|
* 2: if set j is contained in set i |
|
* 3: the sets are equivalent |
|
*/ |
|
|
|
static int |
|
compare_sets(struct attr_set* set, int i, int j) |
|
{ |
|
int k,l,numI,numJ; |
|
int common=0; |
|
int result=0; |
|
|
|
if (( set[i].attrs == NULL ) && ( set[j].attrs == NULL )) |
|
return 3; |
|
|
|
if ( set[i].attrs == NULL ) |
|
return 2; |
|
|
|
if ( set[j].attrs == NULL ) |
|
return 1; |
|
|
|
numI = set[i].count; |
|
numJ = set[j].count; |
|
|
|
for ( l=0; l < numI; l++ ) { |
|
for ( k = 0; k < numJ; k++ ) { |
|
if ( strcmp( set[i].attrs[l].an_name.bv_val, |
|
set[j].attrs[k].an_name.bv_val ) == 0 ) |
|
common++; |
|
} |
|
} |
|
|
|
if ( common == numI ) |
|
result = 1; |
|
|
|
if ( common == numJ ) |
|
result += 2; |
|
|
|
return result; |
|
} |
} |
|
|
static slap_overinst proxy_cache; |
static slap_overinst proxy_cache; |
Line 1921 int pcache_init()
|
Line 2094 int pcache_init()
|
at = ldap_str2attributetype( queryid_schema, &code, &err, |
at = ldap_str2attributetype( queryid_schema, &code, &err, |
LDAP_SCHEMA_ALLOW_ALL ); |
LDAP_SCHEMA_ALLOW_ALL ); |
if ( !at ) { |
if ( !at ) { |
fprintf( stderr, "AttributeType Load failed %s %s\n", |
Debug( LDAP_DEBUG_ANY, |
ldap_scherr2str(code), err ); |
"pcache_init: ldap_str2attributetype failed %s %s\n", |
|
ldap_scherr2str(code), err, 0 ); |
return code; |
return code; |
} |
} |
code = at_add( at, &err ); |
code = at_add( at, 0, NULL, &err ); |
if ( !code ) { |
if ( !code ) { |
slap_str2ad( at->at_names[0], &ad_queryid, &err ); |
slap_str2ad( at->at_names[0], &ad_queryid, &err ); |
} |
} |
ldap_memfree( at ); |
ldap_memfree( at ); |
if ( code ) { |
if ( code ) { |
fprintf( stderr, "AttributeType Load failed %s %s\n", |
Debug( LDAP_DEBUG_ANY, |
scherr2str(code), err ); |
"pcache_init: at_add failed %s %s\n", |
|
scherr2str(code), err, 0 ); |
return code; |
return code; |
} |
} |
|
|
proxy_cache.on_bi.bi_type = "proxycache"; |
proxy_cache.on_bi.bi_type = "pcache"; |
proxy_cache.on_bi.bi_db_init = proxy_cache_init; |
proxy_cache.on_bi.bi_db_init = proxy_cache_init; |
proxy_cache.on_bi.bi_db_config = proxy_cache_config; |
proxy_cache.on_bi.bi_db_config = proxy_cache_config; |
proxy_cache.on_bi.bi_db_open = proxy_cache_open; |
proxy_cache.on_bi.bi_db_open = proxy_cache_open; |
Line 1944 int pcache_init()
|
Line 2119 int pcache_init()
|
proxy_cache.on_bi.bi_db_destroy = proxy_cache_destroy; |
proxy_cache.on_bi.bi_db_destroy = proxy_cache_destroy; |
proxy_cache.on_bi.bi_op_search = proxy_cache_search; |
proxy_cache.on_bi.bi_op_search = proxy_cache_search; |
|
|
|
proxy_cache.on_bi.bi_chk_controls = proxy_cache_chk_controls; |
|
|
|
proxy_cache.on_bi.bi_cf_ocs = pcocs; |
|
|
|
code = config_register_schema( pccfg, pcocs ); |
|
if ( code ) return code; |
|
|
return overlay_register( &proxy_cache ); |
return overlay_register( &proxy_cache ); |
} |
} |
|
|