]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
More for back-mdb multival
authorHoward Chu <hyc@openldap.org>
Thu, 30 Aug 2018 10:24:25 +0000 (11:24 +0100)
committerHoward Chu <hyc@openldap.org>
Thu, 30 Aug 2018 10:24:25 +0000 (11:24 +0100)
Allow configuring thresholds for specific attributes

doc/man/man5/slapd-mdb.5
servers/slapd/back-mdb/attr.c
servers/slapd/back-mdb/back-mdb.h
servers/slapd/back-mdb/config.c
servers/slapd/back-mdb/id2entry.c
servers/slapd/back-mdb/index.c
servers/slapd/back-mdb/modify.c
servers/slapd/back-mdb/proto-mdb.h

index 3949a4baee1d001fb61a831370e95bb0af9fd7c3..cc7d51f50c4c4e129883d734413e32774f57f9db 100644 (file)
@@ -167,23 +167,22 @@ Specify the file protection mode that newly created database
 files should have.
 The default is 0600.
 .TP
-.BI multival_hi \ <integer>
-Specify the number of values above which a multivalued attribute is
+\fBmultival \fR{\fI<attrlist>\fR|\fBdefault\fR} \fI<integer hi>\fR,\fI<integer lo>
+Specify the number of values for which a multivalued attribute is
 stored in a separate table. Normally entries are stored as a single
 blob inside the database. When an entry gets very large or contains
 attributes with a very large number of values, modifications on that
 entry may get very slow. Splitting the large attributes out to a separate
 table can improve the performance of modification operations.
-The default is UINT_MAX, which keeps all attributes in the main blob.
-.TP
-.BI multival_lo \ <integer>
-Specify the number of values below which a multivalued attribute
-that was stored in a separate table is moved back into the main
-entry blob. If a modification deletes enough values to bring an
-attribute below this threshold, its values will be removed from the
-separate table and merged back into the main entry blob.
-The default is UINT_MAX, which keeps all attributes in
-the main blob.
+The threshold is specified as a pair of integers. If the number of
+values exceeds the hi threshold the values will be split out. If
+a modification deletes enough values to bring an attribute below
+the lo threshold the values will be removed from the separate
+table and merged back into the main entry blob.
+The threshold can be set for a specific list of attributes, or
+the default can be configured for all other attributes.
+The default value for both hi and lo thresholds is UINT_MAX, which keeps
+all attributes in the main blob.
 .TP
 .BI rtxnsize \ <entries>
 Specify the maximum number of entries to process in a single read
index b9eba4d029709f36fca160a125a58db4c88334eb..3473e7b77a5558fecd32273b117565c32d0b0205 100644 (file)
@@ -122,6 +122,8 @@ mdb_attr_dbs_open(
        for ( i=0; i<mdb->mi_nattrs; i++ ) {
                if ( mdb->mi_attrs[i]->ai_dbi ) /* already open */
                        continue;
+               if ( !mdb->mi_attrs[i]->ai_indexmask )  /* not an index record */
+                       continue;
                rc = mdb_dbi_open( txn, mdb->mi_attrs[i]->ai_desc->ad_type->sat_cname.bv_val,
                        flags, &mdb->mi_attrs[i]->ai_dbi );
                if ( rc ) {
@@ -384,6 +386,8 @@ fail:
                a->ai_root = NULL;
                a->ai_desc = ad;
                a->ai_dbi = 0;
+               a->ai_multi_hi = UINT_MAX;
+               a->ai_multi_lo = UINT_MAX;
 
                if ( mdb->mi_flags & MDB_IS_OPEN ) {
                        a->ai_indexmask = 0;
@@ -494,7 +498,160 @@ mdb_attr_index_unparse( struct mdb_info *mdb, BerVarray *bva )
                mdb_attr_index_unparser( &aidef, bva );
        }
        for ( i=0; i<mdb->mi_nattrs; i++ )
-               mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
+               if ( mdb->mi_attrs[i]->ai_indexmask )
+                       mdb_attr_index_unparser( mdb->mi_attrs[i], bva );
+}
+
+int
+mdb_attr_multi_config(
+       struct mdb_info *mdb,
+       const char              *fname,
+       int                     lineno,
+       int                     argc,
+       char            **argv,
+       struct          config_reply_s *c_reply)
+{
+       int rc = 0;
+       int     i;
+       unsigned hi,lo;
+       char **attrs, *next, *s;
+
+       attrs = ldap_str2charray( argv[0], "," );
+
+       if( attrs == NULL ) {
+               fprintf( stderr, "%s: line %d: "
+                       "no attributes specified: %s\n",
+                       fname, lineno, argv[0] );
+               return LDAP_PARAM_ERROR;
+       }
+
+       hi = strtoul( argv[1], &next, 10 );
+       if ( next == argv[1] || next[0] != ',' )
+               goto badval;
+       s = next+1;
+       lo = strtoul( s, &next, 10 );
+       if ( next == s || next[0] != '\0' )
+               goto badval;
+
+       if ( lo >= hi ) {
+badval:
+               snprintf(c_reply->msg, sizeof(c_reply->msg),
+                       "invalid hi/lo thresholds" );
+               fprintf( stderr, "%s: line %d: %s\n",
+                       fname, lineno, c_reply->msg );
+               return LDAP_PARAM_ERROR;
+       }
+
+       for ( i = 0; attrs[i] != NULL; i++ ) {
+               AttrInfo        *a;
+               AttributeDescription *ad;
+               const char *text;
+
+               if( strcasecmp( attrs[i], "default" ) == 0 ) {
+                       mdb->mi_multi_hi = hi;
+                       mdb->mi_multi_lo = lo;
+                       continue;
+               }
+
+               ad = NULL;
+               rc = slap_str2ad( attrs[i], &ad, &text );
+
+               if( rc != LDAP_SUCCESS ) {
+                       if ( c_reply )
+                       {
+                               snprintf(c_reply->msg, sizeof(c_reply->msg),
+                                       "multival attribute \"%s\" undefined",
+                                       attrs[i] );
+
+                               fprintf( stderr, "%s: line %d: %s\n",
+                                       fname, lineno, c_reply->msg );
+                       }
+fail:
+                       goto done;
+               }
+
+               a = (AttrInfo *) ch_calloc( 1, sizeof(AttrInfo) );
+
+               a->ai_desc = ad;
+               a->ai_multi_hi = hi;
+               a->ai_multi_lo = lo;
+
+               rc = ainfo_insert( mdb, a );
+               if( rc ) {
+                       if (c_reply) {
+                               snprintf(c_reply->msg, sizeof(c_reply->msg),
+                                       "duplicate multival definition for attr \"%s\"",
+                                       attrs[i] );
+                               fprintf( stderr, "%s: line %d: %s\n",
+                                       fname, lineno, c_reply->msg );
+                       }
+
+                       rc = LDAP_PARAM_ERROR;
+                       goto done;
+               }
+       }
+
+done:
+       ldap_charray_free( attrs );
+
+       return rc;
+}
+
+static int
+mdb_attr_multi_unparser( void *v1, void *v2 )
+{
+       AttrInfo *ai = v1;
+       BerVarray *bva = v2;
+       struct berval bv;
+       char digbuf[sizeof("4294967296,4294967296")];
+       char *ptr;
+
+       bv.bv_len = snprintf( digbuf, sizeof(digbuf), "%u,%u",
+               ai->ai_multi_hi, ai->ai_multi_lo );
+       if ( bv.bv_len ) {
+               bv.bv_len += ai->ai_desc->ad_cname.bv_len + 1;
+               ptr = ch_malloc( bv.bv_len+1 );
+               bv.bv_val = lutil_strcopy( ptr, ai->ai_desc->ad_cname.bv_val );
+               *bv.bv_val++ = ' ';
+               strcpy(bv.bv_val, digbuf);
+               bv.bv_val = ptr;
+               ber_bvarray_add( bva, &bv );
+       }
+       return 0;
+}
+
+void
+mdb_attr_multi_unparse( struct mdb_info *mdb, BerVarray *bva )
+{
+       int i;
+
+       if ( mdb->mi_multi_hi < UINT_MAX ) {
+               aidef.ai_multi_hi = mdb->mi_multi_hi;
+               aidef.ai_multi_lo = mdb->mi_multi_lo;
+               mdb_attr_multi_unparser( &aidef, bva );
+       }
+       for ( i=0; i<mdb->mi_nattrs; i++ )
+               if ( mdb->mi_attrs[i]->ai_multi_hi < UINT_MAX )
+                       mdb_attr_multi_unparser( mdb->mi_attrs[i], bva );
+}
+
+void
+mdb_attr_multi_thresh( struct mdb_info *mdb, AttributeDescription *ad, unsigned *hi, unsigned *lo )
+{
+       AttrInfo *ai = mdb_attr_mask( mdb, ad );
+       if ( ai && ai->ai_multi_hi < UINT_MAX )
+       {
+               if ( hi )
+                       *hi = ai->ai_multi_hi;
+               if ( lo )
+                       *lo = ai->ai_multi_lo;
+       } else
+       {
+               if ( hi )
+                       *hi = mdb->mi_multi_hi;
+               if ( lo )
+                       *lo = mdb->mi_multi_lo;
+       }
 }
 
 void
index 91cbf8d228ba4bb234e255a37e45007099186568..e1966043f63d0d4165255842f4e2489c9503fb11 100644 (file)
@@ -147,6 +147,8 @@ typedef struct mdb_attrinfo {
        MDB_cursor *ai_cursor;  /* for tools */
        int ai_idx;     /* position in AI array */
        MDB_dbi ai_dbi;
+       unsigned ai_multi_hi;
+       unsigned ai_multi_lo;
 } AttrInfo;
 
 /* tool threaded indexer state */
index 82ffa92c412500daed4e8cd9c02f0f6e422f36bc..56ed89017d165ef6ce085f18bd33efb68e13f603 100644 (file)
@@ -40,6 +40,7 @@ enum {
        MDB_MAXSIZE,
        MDB_MODE,
        MDB_SSTACK,
+       MDB_MULTIVAL,
 };
 
 static ConfigTable mdbcfg[] = {
@@ -83,16 +84,11 @@ static ConfigTable mdbcfg[] = {
                mdb_cf_gen, "( OLcfgDbAt:0.3 NAME 'olcDbMode' "
                "DESC 'Unix permissions of database files' "
                "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
-       { "multival_hi", "num", 2, 2, 0, ARG_UINT|ARG_OFFSET,
-               (void *)offsetof(struct mdb_info, mi_multi_hi),
-               "( OLcfgDbAt:12.6 NAME 'olcDbMultivalHi' "
-               "DESC 'Threshold for splitting multivalued attr out of main blob' "
-               "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
-       { "multival_lo", "num", 2, 2, 0, ARG_UINT|ARG_OFFSET,
-               (void *)offsetof(struct mdb_info, mi_multi_lo),
-               "( OLcfgDbAt:12.7 NAME 'olcDbMultivalLo' "
-               "DESC 'Threshold for consolidating multivalued attr back into main blob' "
-               "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+       { "multival", "attr> <hi,lo", 3, 3, 0, ARG_MAGIC|MDB_MULTIVAL,
+               mdb_cf_gen,
+               "( OLcfgDbAt:12.6 NAME 'olcDbMultival' "
+               "DESC 'Hi/Lo thresholds for splitting multivalued attr out of main blob' "
+               "SYNTAX OMsDirectoryString )", NULL, NULL },
        { "rtxnsize", "entries", 2, 2, 0, ARG_UINT|ARG_OFFSET,
                (void *)offsetof(struct mdb_info, mi_rtxn_size),
                "( OLcfgDbAt:12.5 NAME 'olcDbRtxnSize' "
@@ -116,7 +112,7 @@ static ConfigOCs mdbocs[] = {
                "MAY ( olcDbCheckpoint $ olcDbEnvFlags $ "
                "olcDbNoSync $ olcDbIndex $ olcDbMaxReaders $ olcDbMaxSize $ "
                "olcDbMode $ olcDbSearchStack $ olcDbMaxEntrySize $ olcDbRtxnSize $ "
-               "olcDbMultivalHi $ olcDbMultivalLo ) )",
+               "olcDbMultival ) )",
                        Cft_Database, mdbcfg },
        { NULL, 0, NULL }
 };
@@ -357,6 +353,11 @@ mdb_cf_gen( ConfigArgs *c )
                case MDB_MAXSIZE:
                        c->value_ulong = mdb->mi_mapsize;
                        break;
+
+               case MDB_MULTIVAL:
+                       mdb_attr_multi_unparse( mdb, &c->rvalue_vals );
+                       if ( !c->rvalue_vals ) rc = 1;
+                       break;
                }
                return rc;
        } else if ( c->op == LDAP_MOD_DELETE ) {
@@ -489,6 +490,61 @@ mdb_cf_gen( ConfigArgs *c )
                                }
                        }
                        break;
+               case MDB_MULTIVAL:
+                       if ( c->valx == -1 ) {
+                               int i;
+
+                               /* delete all */
+                               for ( i = 0; i < mdb->mi_nattrs; i++ ) {
+                                       mdb->mi_attrs[i]->ai_multi_hi = UINT_MAX;
+                                       mdb->mi_attrs[i]->ai_multi_lo = UINT_MAX;
+                               }
+                               mdb->mi_multi_hi = UINT_MAX;
+                               mdb->mi_multi_lo = UINT_MAX;
+
+                       } else {
+                               struct berval bv, def = BER_BVC("default");
+                               char *ptr;
+
+                               for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);
+
+                               bv.bv_val = c->line;
+                               bv.bv_len = ptr - bv.bv_val;
+                               if ( bvmatch( &bv, &def )) {
+                                       mdb->mi_multi_hi = UINT_MAX;
+                                       mdb->mi_multi_lo = UINT_MAX;
+
+                               } else {
+                                       int i;
+                                       char **attrs;
+                                       char sep;
+
+                                       sep = bv.bv_val[ bv.bv_len ];
+                                       bv.bv_val[ bv.bv_len ] = '\0';
+                                       attrs = ldap_str2charray( bv.bv_val, "," );
+
+                                       for ( i = 0; attrs[ i ]; i++ ) {
+                                               AttributeDescription *ad = NULL;
+                                               const char *text;
+                                               AttrInfo *ai;
+
+                                               slap_str2ad( attrs[ i ], &ad, &text );
+                                               /* if we got here... */
+                                               assert( ad != NULL );
+
+                                               ai = mdb_attr_mask( mdb, ad );
+                                               /* if we got here... */
+                                               assert( ai != NULL );
+
+                                               ai->ai_multi_hi = UINT_MAX;
+                                               ai->ai_multi_lo = UINT_MAX;
+                                       }
+
+                                       bv.bv_val[ bv.bv_len ] = sep;
+                                       ldap_charray_free( attrs );
+                               }
+                       }
+                       break;
                }
                return rc;
        }
@@ -694,6 +750,12 @@ mdb_cf_gen( ConfigArgs *c )
                }
                break;
 
+       case MDB_MULTIVAL:
+               rc = mdb_attr_multi_config( mdb, c->fname, c->lineno,
+                       c->argc - 1, &c->argv[1], &c->reply);
+
+               if( rc != LDAP_SUCCESS ) return 1;
+               break;
        }
        return 0;
 }
index e5c856a33f76a14a9dc6cd8a126ed52bfcc68126..e15dddefa960f9d1717b64a1182461f2264b6612 100644 (file)
@@ -838,6 +838,7 @@ static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
        ber_len_t len, dlen;
        int i, nat = 0, nval = 0, nnval = 0, doff = 0;
        Attribute *a;
+       unsigned hi;
 
        eh->multi = NULL;
        len = 4*sizeof(int);    /* nattrs, nvals, ocflags, offset */
@@ -858,7 +859,8 @@ static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
                len += 2*sizeof(int);   /* AD index, numvals */
                dlen += 2*sizeof(int);
                nval += a->a_numvals + 1;       /* empty berval at end */
-               if (a->a_numvals > mdb->mi_multi_hi)
+               mdb_attr_multi_thresh( mdb, a->a_desc, &hi, NULL );
+               if (a->a_numvals > hi)
                        a->a_flags |= SLAP_ATTR_BIG_MULTI;
                if (a->a_flags & SLAP_ATTR_BIG_MULTI)
                        doff += a->a_numvals;
index 67790816f7157a3c778dd167fce6ab2cd0141e87..cf3e097708ba09786a198d62308f668206dcc703 100644 (file)
@@ -312,7 +312,7 @@ static int index_at_values(
        /* If this type has no AD, we've never used it before */
        if( type->sat_ad ) {
                ai = mdb_attr_mask( op->o_bd->be_private, type->sat_ad );
-               if ( ai ) {
+               if ( ai && ( ai->ai_indexmask || ai->ai_newmask )) {
 #ifdef LDAP_COMP_MATCH
                        /* component indexing */
                        if ( ai->ai_cr ) {
@@ -351,7 +351,7 @@ static int index_at_values(
                if( desc ) {
                        ai = mdb_attr_mask( op->o_bd->be_private, desc );
 
-                       if( ai ) {
+                       if( ai && ( ai->ai_indexmask || ai->ai_newmask )) {
                                if ( opid == MDB_INDEX_UPDATE_OP )
                                        mask = ai->ai_newmask & ~ai->ai_indexmask;
                                else
index 3049e8a87b83982c7a4e07d44e23c993a9f6864b..9e4bf911ff6f1abd5fb8216a07fdac78f69b2d93 100644 (file)
@@ -173,12 +173,14 @@ do_add:
                                Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
                                        err, *text, 0);
                        } else {
+                               unsigned hi;
                                if (!aold)
                                        anew = attr_find( e->e_attrs, mod->sm_desc );
                                else
                                        anew = aold;
+                               mdb_attr_multi_thresh( mdb, mod->sm_desc, &hi, NULL );
                                /* check for big multivalued attrs */
-                               if ( anew->a_numvals > mdb->mi_multi_hi )
+                               if ( anew->a_numvals > hi )
                                        anew->a_flags |= SLAP_ATTR_BIG_MULTI;
                                if ( anew->a_flags & SLAP_ATTR_BIG_MULTI ) {
                                        if (!mvc) {
@@ -247,7 +249,9 @@ do_del:
                                        if ( mod->sm_numvals ) {
                                                anew = attr_find( e->e_attrs, mod->sm_desc );
                                                if ( anew ) {
-                                                       if ( anew->a_numvals < mdb->mi_multi_lo ) {
+                                                       unsigned lo;
+                                                       mdb_attr_multi_thresh( mdb, mod->sm_desc, NULL, &lo );
+                                                       if ( anew->a_numvals < lo ) {
                                                                anew->a_flags ^= SLAP_ATTR_BIG_MULTI;
                                                                anew = NULL;
                                                        } else {
@@ -280,6 +284,7 @@ do_del:
                                Debug(LDAP_DEBUG_ARGS, "mdb_modify_internal: %d %s\n",
                                        err, *text, 0);
                        } else {
+                               unsigned hi;
                                got_delete = 1;
                                if (a_flags & SLAP_ATTR_BIG_MULTI) {
                                        Attribute a_dummy;
@@ -297,7 +302,8 @@ do_del:
                                                goto mval_fail;
                                }
                                anew = attr_find( e->e_attrs, mod->sm_desc );
-                               if (mod->sm_numvals > mdb->mi_multi_hi) {
+                               mdb_attr_multi_thresh( mdb, mod->sm_desc, &hi, NULL );
+                               if (mod->sm_numvals > hi) {
                                        anew->a_flags |= SLAP_ATTR_BIG_MULTI;
                                        if (!mvc) {
                                                err = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
index 126eaf0b3fb99fabf5854e329bea63e47d709b6a..c194c46b1d9c1adc6dcd90e1cae10c7cc8db329c 100644 (file)
@@ -44,6 +44,15 @@ void mdb_attr_index_destroy LDAP_P(( struct mdb_info *mdb ));
 void mdb_attr_index_free LDAP_P(( struct mdb_info *mdb,
        AttributeDescription *ad ));
 
+int mdb_attr_multi_config LDAP_P(( struct mdb_info *mdb,
+       const char *fname, int lineno,
+       int argc, char **argv, struct config_reply_s *cr ));
+
+void mdb_attr_multi_unparse LDAP_P(( struct mdb_info *mdb, BerVarray *bva ));
+
+void mdb_attr_multi_thresh LDAP_P(( struct mdb_info *mdb, AttributeDescription *ad,
+       unsigned *hi, unsigned *lo ));
+
 void mdb_attr_info_free( AttrInfo *ai );
 
 int mdb_ad_read( struct mdb_info *mdb, MDB_txn *txn );