📄 pcache.c
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/pcache.c,v 1.41.2.17 2007/01/02 21:44:08 kurt Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2003-2007 The OpenLDAP Foundation. * Portions Copyright 2003 IBM Corporation. * Portions Copyright 2003 Symas Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by Apurva Kumar for inclusion * in OpenLDAP Software and subsequently rewritten by Howard Chu. */#include "portable.h"#ifdef SLAPD_OVER_PROXYCACHE#include <stdio.h>#include <ac/string.h>#include <ac/time.h>#include "slap.h"#include "lutil.h"#include "ldap_rq.h"#include "config.h"/* query cache structs *//* query */typedef struct Query_s { Filter* filter; /* Search Filter */ AttributeName* attrs; /* Projected attributes */ AttributeName* save_attrs; /* original attributes, saved for response */ struct berval base; /* Search Base */ int scope; /* Search scope */} Query;/* struct representing a cached query */typedef struct cached_query_s { Query query; /* LDAP query */ struct berval q_uuid; /* query identifier */ int template_id; /* template of the query */ time_t expiry_time; /* time till the query is considered valid */ struct cached_query_s *next; /* next query in the template */ struct cached_query_s *prev; /* previous query in the template */ struct cached_query_s *lru_up; /* previous query in the LRU list */ struct cached_query_s *lru_down; /* next query in the LRU list */} CachedQuery;/* struct representing a query template * e.g. template string = &(cn=)(mail=) */typedef struct query_template_s { struct berval querystr; /* Filter string corresponding to the QT */ int attr_set_index; /* determines the projected attributes */ CachedQuery* query; /* most recent query cached for the template */ CachedQuery* query_last; /* oldest query cached for the template */ int no_of_queries; /* Total number of queries in the template */ time_t ttl; /* TTL for the queries of this template */ time_t negttl; /* TTL for negative results */ ldap_pvt_thread_rdwr_t t_rwlock; /* Rd/wr lock for accessing queries in the template */} QueryTemplate;/* * Represents a set of projected attributes. */struct attr_set { unsigned flags;#define PC_CONFIGURED (0x1)#define PC_REFERENCED (0x2)#define PC_GOT_OC (0x4) AttributeName* attrs; /* specifies the set */ int count; /* number of attributes */};struct query_manager_s;/* prototypes for functions for 1) query containment * 2) query addition, 3) cache replacement */typedef CachedQuery * (QCfunc)(Operation *op, struct query_manager_s*, Query*, int );typedef void (AddQueryfunc)(struct query_manager_s*, Query*, int, struct berval*);typedef void (CRfunc)(struct query_manager_s*, struct berval * );/* LDAP query cache */typedef struct query_manager_s { struct attr_set* attr_sets; /* possible sets of projected attributes */ QueryTemplate* templates; /* cacheable templates */ CachedQuery* lru_top; /* top and bottom of LRU list */ CachedQuery* lru_bottom; ldap_pvt_thread_mutex_t lru_mutex; /* mutex for accessing LRU list */ /* Query cache methods */ QCfunc *qcfunc; /* Query containment*/ CRfunc *crfunc; /* cache replacement */ AddQueryfunc *addfunc; /* add query */} query_manager;/* LDAP query cache manager */typedef struct cache_manager_s { BackendDB db; /* underlying database */ unsigned long num_cached_queries; /* total number of cached queries */ unsigned long max_queries; /* upper bound on # of cached queries */ int numattrsets; /* number of attribute sets */ int numtemplates; /* number of cacheable templates */ int cur_entries; /* current number of entries cached */ int max_entries; /* max number of entries cached */ int num_entries_limit; /* max # of entries in a cacheable query */ char response_cb; /* install the response callback * at the tail of the callback list */#define PCACHE_RESPONSE_CB_HEAD 0#define PCACHE_RESPONSE_CB_TAIL 1 time_t cc_period; /* interval between successive consistency checks (sec) */ int cc_paused; void *cc_arg; ldap_pvt_thread_mutex_t cache_mutex; query_manager* qm; /* query cache managed by the cache manager */} cache_manager;static int pcache_debug;static AttributeDescription *ad_queryid;static char *queryid_schema = "( 1.3.6.1.4.1.4203.666.1.12 NAME 'queryid' " "DESC 'list of queries the entry belongs to' " "EQUALITY octetStringMatch " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} " "NO-USER-MODIFICATION USAGE directoryOperation )";/* Return 1 for an added entry, else 0 */static intmerge_entry( Operation *op, Entry *e, struct berval* query_uuid ){ int rc; Modifications* modlist = NULL; const char* text = NULL; Attribute *attr; char textbuf[SLAP_TEXT_BUFLEN]; size_t textlen = sizeof(textbuf); SlapReply sreply = {REP_RESULT}; slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; attr = e->e_attrs; e->e_attrs = NULL; /* add queryid attribute */ attr_merge_one( e, ad_queryid, query_uuid, NULL ); /* append the attribute list from the fetched entry */ e->e_attrs->a_next = attr; op->o_tag = LDAP_REQ_ADD; op->o_protocol = LDAP_VERSION3; op->o_callback = &cb; op->o_time = slap_get_time(); op->o_do_not_cache = 1; op->ora_e = e; op->o_req_dn = e->e_name; op->o_req_ndn = e->e_nname; rc = op->o_bd->be_add( op, &sreply ); if ( rc != LDAP_SUCCESS ) { if ( rc == LDAP_ALREADY_EXISTS ) { slap_entry2mods( e, &modlist, &text, textbuf, textlen ); modlist->sml_op = LDAP_MOD_ADD; op->o_tag = LDAP_REQ_MODIFY; op->orm_modlist = modlist; op->o_bd->be_modify( op, &sreply ); slap_mods_free( modlist, 1 ); } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) { syncrepl_add_glue( op, e ); e = NULL; rc = 1; } if ( e ) { entry_free( e ); rc = 0; } } else { be_entry_release_w( op, e ); rc = 1; } return rc;}/* compare base and scope of incoming and cached queries */static int base_scope_compare( struct berval* ndn_stored, struct berval* ndn_incoming, int scope_stored, int scope_incoming ){ struct berval pdn_incoming = BER_BVNULL; if (scope_stored < scope_incoming) return 0; if ( !dnIsSuffix(ndn_incoming, ndn_stored)) return 0; switch(scope_stored) { case LDAP_SCOPE_BASE: return (ndn_incoming->bv_len == ndn_stored->bv_len); case LDAP_SCOPE_ONELEVEL: switch(scope_incoming){ case LDAP_SCOPE_BASE: dnParent(ndn_incoming, &pdn_incoming); return (pdn_incoming.bv_len == ndn_stored->bv_len); case LDAP_SCOPE_ONELEVEL: return (ndn_incoming->bv_len == ndn_stored->bv_len); default: return 0; } case LDAP_SCOPE_SUBTREE: return 1; break; default: return 0; break; }}/* add query on top of LRU list */static voidadd_query_on_top (query_manager* qm, CachedQuery* qc){ CachedQuery* top = qm->lru_top; Query* q = (Query*)qc; qm->lru_top = qc; if (top) top->lru_up = qc; else qm->lru_bottom = qc; qc->lru_down = top; qc->lru_up = NULL; Debug( pcache_debug, "Base of added query = %s\n", q->base.bv_val, 0, 0 );}/* remove_query from LRU list */static voidremove_query (query_manager* qm, CachedQuery* qc){ CachedQuery* up; CachedQuery* down; if (!qc) return; up = qc->lru_up; down = qc->lru_down; if (!up) qm->lru_top = down; if (!down) qm->lru_bottom = up; if (down) down->lru_up = up; if (up) up->lru_down = down; qc->lru_up = qc->lru_down = NULL;}/* find and remove string2 from string1 * from start if position = 1, * from end if position = 3, * from anywhere if position = 2 * string1 is overwritten if position = 2. */static intfind_and_remove(struct berval* ber1, struct berval* ber2, int position){ int ret=0; if ( !ber2->bv_val ) return 1; if ( !ber1->bv_val ) return 0; switch( position ) { case 1: if ( ber1->bv_len >= ber2->bv_len && !memcmp( ber1->bv_val, ber2->bv_val, ber2->bv_len )) { ret = 1; ber1->bv_val += ber2->bv_len; ber1->bv_len -= ber2->bv_len; } break; case 2: { char *temp; ber1->bv_val[ber1->bv_len] = '\0'; temp = strstr( ber1->bv_val, ber2->bv_val ); if ( temp ) { strcpy( temp, temp+ber2->bv_len ); ber1->bv_len -= ber2->bv_len; ret = 1; } break; } case 3: if ( ber1->bv_len >= ber2->bv_len && !memcmp( ber1->bv_val+ber1->bv_len-ber2->bv_len, ber2->bv_val, ber2->bv_len )) { ret = 1; ber1->bv_len -= ber2->bv_len; } break; } return ret;}static struct berval*merge_init_final(Operation *op, struct berval* init, struct berval* any, struct berval* final){ struct berval* merged, *temp; int i, any_count, count; for (any_count=0; any && any[any_count].bv_val; any_count++) ; count = any_count; if (init->bv_val) count++; if (final->bv_val) count++; merged = (struct berval*)op->o_tmpalloc( (count+1)*sizeof(struct berval), op->o_tmpmemctx ); temp = merged; if (init->bv_val) { ber_dupbv_x( temp, init, op->o_tmpmemctx ); temp++; } for (i=0; i<any_count; i++) { ber_dupbv_x( temp, any, op->o_tmpmemctx ); temp++; any++; } if (final->bv_val){ ber_dupbv_x( temp, final, op->o_tmpmemctx ); temp++; } BER_BVZERO( temp ); return merged;}/* Each element in stored must be found in incoming. Incoming is overwritten. */static intstrings_containment(struct berval* stored, struct berval* incoming){ struct berval* element; int k=0; int j, rc = 0; for ( element=stored; element->bv_val != NULL; element++ ) { for (j = k; incoming[j].bv_val != NULL; j++) { if (find_and_remove(&(incoming[j]), element, 2)) { k = j; rc = 1; break; } rc = 0; } if ( rc ) { continue; } else { return 0; } } return 1;}static intsubstr_containment_substr(Operation *op, Filter* stored, Filter* incoming){ int i; int rc = 0; struct berval init_incoming; struct berval final_incoming; struct berval *remaining_incoming = NULL; if ((!(incoming->f_sub_initial.bv_val) && (stored->f_sub_initial.bv_val)) || (!(incoming->f_sub_final.bv_val) && (stored->f_sub_final.bv_val))) return 0; init_incoming = incoming->f_sub_initial; final_incoming = incoming->f_sub_final; if (find_and_remove(&init_incoming, &(stored->f_sub_initial), 1) && find_and_remove(&final_incoming, &(stored->f_sub_final), 3)) { if (stored->f_sub_any == NULL) { rc = 1; goto final; } remaining_incoming = merge_init_final(op, &init_incoming, incoming->f_sub_any, &final_incoming); rc = strings_containment(stored->f_sub_any, remaining_incoming); ber_bvarray_free_x( remaining_incoming, op->o_tmpmemctx ); }final: return rc;}static intsubstr_containment_equality(Operation *op, Filter* stored, Filter* incoming){ struct berval incoming_val[2]; int rc = 0; incoming_val[1] = incoming->f_av_value; if (find_and_remove(incoming_val+1, &(stored->f_sub_initial), 1) && find_and_remove(incoming_val+1, &(stored->f_sub_final), 3)) { if (stored->f_sub_any == NULL){ rc = 1; goto final; } ber_dupbv_x( incoming_val, incoming_val+1, op->o_tmpmemctx ); BER_BVZERO( incoming_val+1 ); rc = strings_containment(stored->f_sub_any, incoming_val); op->o_tmpfree( incoming_val[0].bv_val, op->o_tmpmemctx ); }final: return rc;}/* check whether query is contained in any of * the cached queries in template template_index */static CachedQuery *query_containment(Operation *op, query_manager *qm, Query *query, int template_index){ QueryTemplate* templa= qm->templates; CachedQuery* qc; Query* q; Filter* inputf = query->filter; struct berval* base = &(query->base); int scope = query->scope; int res=0; Filter* fs; Filter* fi; int ret, rc; const char* text; MatchingRule* mrule = NULL; if (inputf != NULL) { Debug( pcache_debug, "Lock QC index = %d\n", template_index, 0, 0 ); ldap_pvt_thread_rdwr_rlock(&(templa[template_index].t_rwlock)); for(qc=templa[template_index].query; qc != NULL; qc= qc->next) { q = (Query*)qc; if(base_scope_compare(&(q->base), base, q->scope, scope)) { fi = inputf; fs = q->filter; do { res=0; switch (fs->f_choice) { case LDAP_FILTER_EQUALITY: if (fi->f_choice == LDAP_FILTER_EQUALITY) mrule = fs->f_ava->aa_desc->ad_type->sat_equality; else ret = 1; break; case LDAP_FILTER_GE: case LDAP_FILTER_LE: mrule = fs->f_ava->aa_desc->ad_type->sat_ordering; break; default: mrule = NULL; } if (mrule) { rc = value_match(&ret, fs->f_ava->aa_desc, mrule, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, &(fi->f_ava->aa_value), &(fs->f_ava->aa_value), &text); if (rc != LDAP_SUCCESS) { ldap_pvt_thread_rdwr_runlock(&(templa[template_index].t_rwlock)); Debug( pcache_debug, "Unlock: Exiting QC index=%d\n", template_index, 0, 0 ); return NULL; } } switch (fs->f_choice) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -