]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/pcache.c
Revert prev commit (ITS#5367)
[openldap] / servers / slapd / overlays / pcache.c
index 71e04db825d56d34303df1d6b5aaf11bc6d9d9eb..450706c12751e13454798016afecc6057b54fb95 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2003-2007 The OpenLDAP Foundation.
+ * Copyright 2003-2008 The OpenLDAP Foundation.
  * Portions Copyright 2003 IBM Corporation.
  * Portions Copyright 2003 Symas Corporation.
  * All rights reserved.
@@ -185,15 +185,16 @@ typedef struct cache_manager_s {
        int     numattrsets;                    /* number of attribute sets */
        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 */
+       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
+       char    defer_db_open;                  /* defer open for online add */
 
        time_t  cc_period;              /* interval between successive consistency checks (sec) */
-       int     cc_paused;
+       int     cc_paused;
        void    *cc_arg;
 
        ldap_pvt_thread_mutex_t         cache_mutex;
@@ -1367,8 +1368,7 @@ remove_func (
        attr = attr_find( rs->sr_entry->e_attrs,  ad_queryId );
        if ( attr == NULL ) return 0;
 
-       for ( count = 0; !BER_BVISNULL( &attr->a_vals[count] ); count++ )
-               ;
+       count = attr->a_numvals;
        assert( count > 0 );
        qi = op->o_tmpalloc( sizeof( struct query_info ), op->o_tmpmemctx );
        qi->next = op->o_callback->sc_private;
@@ -1450,6 +1450,7 @@ remove_query_data(
                        mod.sml_type = ad_queryId->ad_cname;
                        mod.sml_values = vals;
                        mod.sml_nvalues = NULL;
+                        mod.sml_numvals = 1;
                        mod.sml_next = NULL;
                        Debug( pcache_debug,
                                "REMOVING TEMP ATTR : TEMPLATE=%s\n",
@@ -1482,67 +1483,91 @@ filter2template(
        int*                    filter_got_oc )
 {
        AttributeDescription *ad;
+       int len, ret;
 
        switch ( f->f_choice ) {
        case LDAP_FILTER_EQUALITY:
                ad = f->f_av_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s=)", ad->ad_cname.bv_val );
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(=)") - 1 );
+               len = STRLENOF( "(=)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s=)", ad->ad_cname.bv_val );
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_GE:
                ad = f->f_av_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s>=)", ad->ad_cname.bv_val);
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(>=)") - 1 );
+               len = STRLENOF( "(>=)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s>=)", ad->ad_cname.bv_val);
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_LE:
                ad = f->f_av_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s<=)", ad->ad_cname.bv_val);
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(<=)") - 1 );
+               len = STRLENOF( "(<=)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s<=)", ad->ad_cname.bv_val);
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_APPROX:
                ad = f->f_av_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s~=)", ad->ad_cname.bv_val);
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(~=)") - 1 );
+               len = STRLENOF( "(~=)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s~=)", ad->ad_cname.bv_val);
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_SUBSTRINGS:
                ad = f->f_sub_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s=)", ad->ad_cname.bv_val );
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(=)") - 1 );
+               len = STRLENOF( "(=)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s=)", ad->ad_cname.bv_val );
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_PRESENT:
                ad = f->f_desc;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%s=*)", ad->ad_cname.bv_val );
-               fstr->bv_len += ad->ad_cname.bv_len + ( sizeof("(=*)") - 1 );
+               len = STRLENOF( "(=*)" ) + ad->ad_cname.bv_len;
+               ret = snprintf( fstr->bv_val+fstr->bv_len, len + 1, "(%s=*)", ad->ad_cname.bv_val );
+               assert( ret == len );
+               fstr->bv_len += len;
                break;
 
        case LDAP_FILTER_AND:
        case LDAP_FILTER_OR:
        case LDAP_FILTER_NOT: {
                int rc = 0;
-               sprintf( fstr->bv_val+fstr->bv_len, "(%c",
-                       f->f_choice == LDAP_FILTER_AND ? '&' :
-                       f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
-               fstr->bv_len += sizeof("(%") - 1;
+               fstr->bv_val[fstr->bv_len++] = '(';
+               switch ( f->f_choice ) {
+               case LDAP_FILTER_AND:
+                       fstr->bv_val[fstr->bv_len] = '&';
+                       break;
+               case LDAP_FILTER_OR:
+                       fstr->bv_val[fstr->bv_len] = '|';
+                       break;
+               case LDAP_FILTER_NOT:
+                       fstr->bv_val[fstr->bv_len] = '!';
+                       break;
+               }
+               fstr->bv_len++;
 
                for ( f = f->f_list; f != NULL; f = f->f_next ) {
                        rc = filter2template( op, f, fstr, filter_attrs, filter_cnt,
                                filter_got_oc );
                        if ( rc ) break;
                }
-               sprintf( fstr->bv_val+fstr->bv_len, ")" );
-               fstr->bv_len += sizeof(")") - 1;
+               fstr->bv_val[fstr->bv_len++] = ')';
+               fstr->bv_val[fstr->bv_len] = '\0';
 
                return rc;
                }
 
        default:
-               strcpy( fstr->bv_val, "(?=?)" );
-               fstr->bv_len += sizeof("(?=?)")-1;
+               /* a filter should at least have room for "()",
+                * an "=" and for a 1-char attr */
+               strcpy( fstr->bv_val, "(?=)" );
+               fstr->bv_len += STRLENOF("(?=)");
                return -1;
        }
 
@@ -1876,14 +1901,19 @@ cache_entries(
        Entry           *e;
        struct berval   crp_uuid;
        char            uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
-       Operation op_tmp = *op;
+       Operation       *op_tmp;
+       Connection      conn = {0};
+       OperationBuffer opbuf;
+       void            *thrctx = ldap_pvt_thread_pool_context();
 
        query_uuid->bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf));
        ber_str2bv(uuidbuf, query_uuid->bv_len, 1, query_uuid);
 
-       op_tmp.o_bd = &cm->db;
-       op_tmp.o_dn = cm->db.be_rootdn;
-       op_tmp.o_ndn = cm->db.be_rootndn;
+       connection_fake_init2( &conn, &opbuf, thrctx, 0 );
+       op_tmp = &opbuf.ob_op;
+       op_tmp->o_bd = &cm->db;
+       op_tmp->o_dn = cm->db.be_rootdn;
+       op_tmp->o_ndn = cm->db.be_rootndn;
 
        Debug( pcache_debug, "UUID for query being added = %s\n",
                        uuidbuf, 0, 0 );
@@ -1893,10 +1923,10 @@ cache_entries(
                e->e_private = NULL;
                while ( cm->cur_entries > (cm->max_entries) ) {
                        BER_BVZERO( &crp_uuid );
-                       remove_query_and_data( &op_tmp, rs, cm, &crp_uuid );
+                       remove_query_and_data( op_tmp, rs, cm, &crp_uuid );
                }
 
-               return_val = merge_entry(&op_tmp, e, query_uuid);
+               return_val = merge_entry(op_tmp, e, query_uuid);
                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                cm->cur_entries += return_val;
                Debug( pcache_debug,
@@ -1958,7 +1988,8 @@ pcache_op_cleanup( Operation *op, SlapReply *rs ) {
                        rs->sr_attrs = si->save_attrs;
                        op->ors_attrs = si->save_attrs;
                }
-               if ( op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
+               if ( (op->o_abandon || rs->sr_err == SLAPD_ABANDON) && 
+                               si->caching_reason == PC_IGNORE ) {
                        filter_free( si->query.filter );
                        if ( si->count ) {
                                /* duplicate query, free it */
@@ -1984,6 +2015,9 @@ pcache_op_cleanup( Operation *op, SlapReply *rs ) {
                                case PC_SIZELIMIT:
                                        qc->q_sizelimit = rs->sr_nentries;
                                        break;
+                               default:
+                                       assert( 0 );
+                                       break;
                                }
                                ldap_pvt_thread_rdwr_wunlock(&qc->rwlock);
                                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
@@ -2181,6 +2215,13 @@ pcache_op_privdb(
                return SLAP_CB_CONTINUE;
        }
 
+       /* The cache DB isn't open yet */
+       if ( cm->defer_db_open ) {
+               send_ldap_error( op, rs, LDAP_UNAVAILABLE,
+                       "pcachePrivDB: cacheDB not available" );
+               return rs->sr_err;
+       }
+
        /* FIXME: might be a little bit exaggerated... */
        if ( !be_isroot( op ) ) {
                save_cb = op->o_callback;
@@ -2253,6 +2294,13 @@ pcache_op_search(
        }
 #endif /* PCACHE_CONTROL_PRIVDB */
 
+       /* The cache DB isn't open yet */
+       if ( cm->defer_db_open ) {
+               send_ldap_error( op, rs, LDAP_UNAVAILABLE,
+                       "pcachePrivDB: cacheDB not available" );
+               return rs->sr_err;
+       }
+
        tempstr.bv_val = op->o_tmpalloc( op->ors_filterstr.bv_len+1, op->o_tmpmemctx );
        tempstr.bv_len = 0;
        if ( filter2template( op, op->ors_filter, &tempstr, &filter_attrs,
@@ -2475,7 +2523,7 @@ consistency_check(
        op->o_dn = cm->db.be_rootdn;
        op->o_ndn = cm->db.be_rootndn;
 
-       cm->cc_arg = arg;
+       cm->cc_arg = arg;
 
        for (templ = qm->templates; templ; templ=templ->qmnext) {
                query = templ->query_last;
@@ -2586,6 +2634,15 @@ static ConfigTable pccfg[] = {
        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
+/* Need to no-op this keyword for dynamic config */
+static ConfigTable pcdummy[] = {
+       { "", "", 0, 0, 0, ARG_IGNORED,
+               NULL, "( OLcfgGlAt:13 NAME 'olcDatabase' "
+                       "DESC 'The backend type for a database instance' "
+                       "SUP olcBackend SINGLE-VALUE X-ORDERED 'SIBLINGS' )", NULL, NULL },
+       { NULL, NULL, 0, 0, 0, ARG_IGNORED }
+};
+
 static ConfigOCs pcocs[] = {
        { "( OLcfgOvOc:2.1 "
                "NAME 'olcPcacheConfig' "
@@ -2597,10 +2654,19 @@ static ConfigOCs pcocs[] = {
        { "( OLcfgOvOc:2.2 "
                "NAME 'olcPcacheDatabase' "
                "DESC 'Cache database configuration' "
-               "AUXILIARY )", Cft_Misc, pccfg, pc_ldadd },
+               "AUXILIARY )", Cft_Misc, pcdummy, pc_ldadd },
        { NULL, 0, NULL }
 };
 
+static int pcache_db_open2( slap_overinst *on, ConfigReply *cr );
+
+static int
+pc_ldadd_cleanup( ConfigArgs *c )
+{
+       slap_overinst *on = c->ca_private;
+       return pcache_db_open2( on, &c->reply );
+}
+
 static int
 pc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
 {
@@ -2614,6 +2680,12 @@ pc_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
        on = (slap_overinst *)p->ce_bi;
        cm = on->on_bi.bi_private;
        ca->be = &cm->db;
+       /* Defer open if this is an LDAPadd */
+       if ( CONFIG_ONLINE_ADD( ca ))
+               ca->cleanup = pc_ldadd_cleanup;
+       else
+               cm->defer_db_open = 0;
+       ca->ca_private = on;
        return LDAP_SUCCESS;
 }
 
@@ -2626,9 +2698,14 @@ pc_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
        struct berval bv;
 
        /* FIXME: should not hardcode "olcDatabase" here */
-       bv.bv_len = sprintf( ca->cr_msg, "olcDatabase=%s", cm->db.bd_info->bi_type );
+       bv.bv_len = snprintf( ca->cr_msg, sizeof( ca->cr_msg ),
+               "olcDatabase=%s", cm->db.bd_info->bi_type );
+       if ( bv.bv_len < 0 || bv.bv_len >= sizeof( ca->cr_msg ) ) {
+               return -1;
+       }
        bv.bv_val = ca->cr_msg;
        ca->be = &cm->db;
+       cm->defer_db_open = 0;
 
        /* We can only create this entry if the database is table-driven
         */
@@ -2798,6 +2875,7 @@ pc_cf_gen( ConfigArgs *c )
                        Debug( LDAP_DEBUG_CONFIG, "%s: %s.\n", c->log, c->cr_msg, 0 );
                        return( 1 );
                }
+
                cm->cc_period = (time_t)t;
                Debug( pcache_debug,
                                "Total # of attribute sets to be cached = %d.\n",
@@ -3065,8 +3143,10 @@ pcache_db_init(
        cm->max_queries = 10000;
        cm->save_queries = 0;
        cm->response_cb = PCACHE_RESPONSE_CB_TAIL;
+       cm->defer_db_open = 1;
        cm->cc_period = 1000;
        cm->cc_paused = 0;
+       cm->cc_arg = NULL;
 
        qm->attr_sets = NULL;
        qm->templates = NULL;
@@ -3121,64 +3201,25 @@ pcache_cachedquery_count_cb( Operation *op, SlapReply *rs )
 }
 
 static int
-pcache_db_open(
-       BackendDB *be,
+pcache_db_open2(
+       slap_overinst *on,
        ConfigReply *cr )
 {
-       slap_overinst   *on = (slap_overinst *)be->bd_info;
        cache_manager   *cm = on->on_bi.bi_private;
        query_manager*  qm = cm->qm;
-       int             i, ncf = 0, rf = 0, nrf = 0, rc = 0;
-
-       /* check attr sets */
-       for ( i = 0; i < cm->numattrsets; i++) {
-               if ( !( qm->attr_sets[i].flags & PC_CONFIGURED ) ) {
-                       if ( qm->attr_sets[i].flags & PC_REFERENCED ) {
-                               Debug( LDAP_DEBUG_CONFIG, "pcache: attr set #%d not configured but referenced.\n", i, 0, 0 );
-                               rf++;
-
-                       } else {
-                               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, attr set #%d not configured.\n", i, 0, 0 );
-                       }
-                       ncf++;
-
-               } else if ( !( qm->attr_sets[i].flags & PC_REFERENCED ) ) {
-                       Debug( LDAP_DEBUG_CONFIG, "pcache: attr set #%d configured but not referenced.\n", i, 0, 0 );
-                       nrf++;
-               }
-       }
-
-       if ( ncf || rf || nrf ) {
-               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, %d attr sets configured but not referenced.\n", nrf, 0, 0 );
-               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, %d attr sets not configured.\n", ncf, 0, 0 );
-               Debug( LDAP_DEBUG_CONFIG, "pcache: %d attr sets not configured but referenced.\n", rf, 0, 0 );
-
-               if ( rf > 0 ) {
-                       return 1;
-               }
-       }
-
-       /* need to inherit something from the original database... */
-       cm->db.be_def_limit = be->be_def_limit;
-       cm->db.be_limits = be->be_limits;
-       cm->db.be_acl = be->be_acl;
-       cm->db.be_dfltaccess = be->be_dfltaccess;
-
-       if ( SLAP_DBMONITORING( be ) ) {
-               SLAP_DBFLAGS( &cm->db ) |= SLAP_DBFLAG_MONITORING;
-
-       } else {
-               SLAP_DBFLAGS( &cm->db ) &= ~SLAP_DBFLAG_MONITORING;
-       }
+       int rc;
 
        rc = backend_startup_one( &cm->db, NULL );
+       if ( rc == 0 ) {
+               cm->defer_db_open = 0;
+       }
 
        /* There is no runqueue in TOOL mode */
-       if ( slapMode & SLAP_SERVER_MODE ) {
+       if (( slapMode & SLAP_SERVER_MODE ) && rc == 0 ) {
                ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
                ldap_pvt_runqueue_insert( &slapd_rq, cm->cc_period,
                        consistency_check, on,
-                       "pcache_consistency", be->be_suffix[0].bv_val );
+                       "pcache_consistency", cm->db.be_suffix[0].bv_val );
                ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
 
                /* Cached database must have the rootdn */
@@ -3276,6 +3317,62 @@ pcache_db_open(
                        rc = 0;
                }
        }
+       return rc;
+}
+
+static int
+pcache_db_open(
+       BackendDB *be,
+       ConfigReply *cr )
+{
+       slap_overinst   *on = (slap_overinst *)be->bd_info;
+       cache_manager   *cm = on->on_bi.bi_private;
+       query_manager*  qm = cm->qm;
+       int             i, ncf = 0, rf = 0, nrf = 0, rc = 0;
+
+       /* check attr sets */
+       for ( i = 0; i < cm->numattrsets; i++) {
+               if ( !( qm->attr_sets[i].flags & PC_CONFIGURED ) ) {
+                       if ( qm->attr_sets[i].flags & PC_REFERENCED ) {
+                               Debug( LDAP_DEBUG_CONFIG, "pcache: attr set #%d not configured but referenced.\n", i, 0, 0 );
+                               rf++;
+
+                       } else {
+                               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, attr set #%d not configured.\n", i, 0, 0 );
+                       }
+                       ncf++;
+
+               } else if ( !( qm->attr_sets[i].flags & PC_REFERENCED ) ) {
+                       Debug( LDAP_DEBUG_CONFIG, "pcache: attr set #%d configured but not referenced.\n", i, 0, 0 );
+                       nrf++;
+               }
+       }
+
+       if ( ncf || rf || nrf ) {
+               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, %d attr sets configured but not referenced.\n", nrf, 0, 0 );
+               Debug( LDAP_DEBUG_CONFIG, "pcache: warning, %d attr sets not configured.\n", ncf, 0, 0 );
+               Debug( LDAP_DEBUG_CONFIG, "pcache: %d attr sets not configured but referenced.\n", rf, 0, 0 );
+
+               if ( rf > 0 ) {
+                       return 1;
+               }
+       }
+
+       /* need to inherit something from the original database... */
+       cm->db.be_def_limit = be->be_def_limit;
+       cm->db.be_limits = be->be_limits;
+       cm->db.be_acl = be->be_acl;
+       cm->db.be_dfltaccess = be->be_dfltaccess;
+
+       if ( SLAP_DBMONITORING( be ) ) {
+               SLAP_DBFLAGS( &cm->db ) |= SLAP_DBFLAG_MONITORING;
+
+       } else {
+               SLAP_DBFLAGS( &cm->db ) &= ~SLAP_DBFLAG_MONITORING;
+       }
+
+       if ( !cm->defer_db_open )
+               rc = pcache_db_open2( on, cr );
 
        return rc;
 }
@@ -3354,6 +3451,7 @@ 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",
@@ -3875,6 +3973,11 @@ pcache_initialize()
        code = config_register_schema( pccfg, pcocs );
        if ( code ) return code;
 
+       {
+               const char *text;
+               code = slap_str2ad( "olcDatabase", &pcdummy[0].ad, &text );
+               if ( code ) return code;
+       }
        return overlay_register( &pcache );
 }