From 9ab30975120649666c5b911fe09d13651b66a1b9 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Tue, 4 Mar 2014 09:35:29 -0800 Subject: [PATCH 167/225] Ticket 346 - version 4 Slow ldapmodify operation time for large quantities of multi-valued attribute values Description: Backported commit f6ef7dc23352c82f45c41dfd5e9392971a164a23 Author: Ludwig Krispenz Bug Description: The reason for the performance degradation is that for operations like add and delete of values and for updating the index for each values a check has tobe done if it exists in the current attribute. if the number of values grows the seaqrch time increases. Fix Description: Keep a secondary array of the indexes of the valuearray which is sorted. To locate a value, a binary search can be used. A design doc is available at: http://port389.org/wiki/Static_group_performance https://fedorahosted.org/389/ticket/346 (cherry picked from commit 890fc22687821279f3862fc0862a4e8d93c00291) --- ldap/servers/slapd/attr.c | 72 +- ldap/servers/slapd/attrlist.c | 2 +- ldap/servers/slapd/attrsyntax.c | 9 + ldap/servers/slapd/back-ldbm/import-threads.c | 2 +- ldap/servers/slapd/back-ldbm/index.c | 26 +- ldap/servers/slapd/back-ldbm/ldbm_attr.c | 6 +- ldap/servers/slapd/computed.c | 2 +- ldap/servers/slapd/entry.c | 177 ++-- ldap/servers/slapd/entrywsi.c | 20 +- ldap/servers/slapd/proto-slap.h | 13 +- ldap/servers/slapd/schema.c | 105 +-- ldap/servers/slapd/slap.h | 8 + ldap/servers/slapd/slapi-plugin.h | 15 +- ldap/servers/slapd/slapi-private.h | 5 +- ldap/servers/slapd/valueset.c | 1077 ++++++++++++------------- 15 files changed, 667 insertions(+), 872 deletions(-) diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c index 87dfe1e..51621e5 100644 --- a/ldap/servers/slapd/attr.c +++ b/ldap/servers/slapd/attr.c @@ -323,11 +323,9 @@ Slapi_Attr * slapi_attr_dup(const Slapi_Attr *attr) { Slapi_Attr *newattr= slapi_attr_new(); - Slapi_Value **present_va= valueset_get_valuearray(&attr->a_present_values); /* JCM Mucking about inside the value set */ - Slapi_Value **deleted_va= valueset_get_valuearray(&attr->a_deleted_values); /* JCM Mucking about inside the value set */ slapi_attr_init(newattr, attr->a_type); - valueset_add_valuearray( &newattr->a_present_values, present_va ); - valueset_add_valuearray( &newattr->a_deleted_values, deleted_va ); + slapi_valueset_set_valueset( &newattr->a_deleted_values, &attr->a_deleted_values ); + slapi_valueset_set_valueset( &newattr->a_present_values, &attr->a_present_values ); newattr->a_deletioncsn= csn_dup(attr->a_deletioncsn); return newattr; } @@ -778,67 +776,25 @@ attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn) } /* - * determine whether we should use an AVL tree of values or not + * add values and check for duplicate values */ - for ( i = 0; vals[i] != NULL; i++ ) ; - numofvals = i; - - /* - * detect duplicate values - */ - if ( numofvals > 1 ) { - /* - * Several values to add: use an AVL tree to detect duplicates. - */ - LDAPDebug( LDAP_DEBUG_TRACE, - "slapi_entry_add_values: using an AVL tree to " - "detect duplicate values\n", 0, 0, 0 ); - - if (valueset_isempty(&a->a_present_values)) { - /* if the attribute contains no values yet, just check the - * input vals array for duplicates - */ - Avlnode *vtree = NULL; - rc= valuetree_add_valuearray(a, vals, &vtree, &duplicate_index); - valuetree_free(&vtree); - was_present_null = 1; + numofvals = valuearray_count(vals); + rc = slapi_valueset_add_attr_valuearray_ext (a, &a->a_present_values, vals, numofvals, SLAPI_VALUE_FLAG_DUPCHECK, &duplicate_index); + if ( rc != LDAP_SUCCESS) { + if (is_type_forbidden(a->a_type)) { + /* If the attr is in the forbidden list + * (e.g., unhashed password), + * we don't return any useful info to the clients. */ + rc = LDAP_OTHER; } else { - /* the attr and vals both contain values, check intersection */ - rc= valueset_intersectswith_valuearray(&a->a_present_values, a, vals, &duplicate_index); - } - - } else if ( !valueset_isempty(&a->a_present_values) ) { - /* - * One or no value to add: don't bother constructing - * an AVL tree, etc. since it probably isn't worth the time. - */ - for ( i = 0; vals[i] != NULL; ++i ) { - if ( slapi_attr_value_find( a, slapi_value_get_berval(vals[i]) ) == 0 ) { - duplicate_index = i; - if (is_type_forbidden(a->a_type)) { - /* If the attr is in the forbidden list - * (e.g., unhashed password), - * we don't return any useful info to the clients. */ - rc = LDAP_OTHER; - } else { - rc = LDAP_TYPE_OR_VALUE_EXISTS; - } - break; - } + rc = LDAP_TYPE_OR_VALUE_EXISTS; } } - /* - * add values if no duplicates detected - */ - if(rc==LDAP_SUCCESS) { - valueset_add_valuearray( &a->a_present_values, vals ); - } - /* In the case of duplicate value, rc == LDAP_TYPE_OR_VALUE_EXISTS or * LDAP_OPERATIONS_ERROR */ - else if ( duplicate_index >= 0 ) { + if ( duplicate_index >= 0 ) { char bvvalcopy[BUFSIZ]; char *duplicate_string = "null or non-ASCII"; @@ -879,7 +835,7 @@ attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn) */ int attr_replace(Slapi_Attr *a, Slapi_Value **vals) { - return valueset_replace(a, &a->a_present_values, vals); + return valueset_replace_valuearray(a, &a->a_present_values, vals); } int diff --git a/ldap/servers/slapd/attrlist.c b/ldap/servers/slapd/attrlist.c index e365f3d..cedf9ea 100644 --- a/ldap/servers/slapd/attrlist.c +++ b/ldap/servers/slapd/attrlist.c @@ -112,7 +112,7 @@ attrlist_merge_valuearray(Slapi_Attr **alist, const char *type, Slapi_Value **va Slapi_Attr **a= NULL; if (!vals) return; attrlist_find_or_create(alist, type, &a); - valueset_add_valuearray( &(*a)->a_present_values, vals ); + slapi_valueset_add_valuearray( *a, &(*a)->a_present_values, vals ); } diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c index 2dabf1f..c0827e2 100644 --- a/ldap/servers/slapd/attrsyntax.c +++ b/ldap/servers/slapd/attrsyntax.c @@ -861,11 +861,20 @@ slapi_attr_is_dn_syntax_attr(Slapi_Attr *attr) const char *syntaxoid = NULL; int dn_syntax = 0; /* not DN, by default */ + if (attr && attr->a_flags & SLAPI_ATTR_FLAG_SYNTAX_IS_DN) + /* it was checked before */ + return(1); + + if (attr && attr->a_plugin == NULL) { + slapi_attr_init_syntax (attr); + } if (attr && attr->a_plugin) { /* If not set, there is no way to get the info */ if ((syntaxoid = attr_get_syntax_oid(attr))) { dn_syntax = ((0 == strcmp(syntaxoid, NAMEANDOPTIONALUID_SYNTAX_OID)) || (0 == strcmp(syntaxoid, DN_SYNTAX_OID))); } + if (dn_syntax) + attr->a_flags |= SLAPI_ATTR_FLAG_SYNTAX_IS_DN; } return dn_syntax; } diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 5667acb..c7d3444 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -2274,7 +2274,7 @@ import_foreman(void *param) /* Setting new entrydn attribute value */ slapi_attr_init(new_entrydn, "entrydn"); - valueset_add_string(&new_entrydn->a_present_values, + valueset_add_string(new_entrydn, &new_entrydn->a_present_values, /* new_dn: duped in valueset_add_string */ (const char *)new_dn, CSN_TYPE_UNKNOWN, NULL); diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c index 66d6e7e..2d5b535 100644 --- a/ldap/servers/slapd/back-ldbm/index.c +++ b/ldap/servers/slapd/back-ldbm/index.c @@ -547,7 +547,7 @@ index_add_mods( for (curr_attr = newe->ep_entry->e_attrs; curr_attr != NULL; curr_attr = curr_attr->a_next) { if (slapi_attr_type_cmp( basetype, curr_attr->a_type, SLAPI_TYPE_CMP_BASE ) == 0) { - valueset_add_valuearray(all_vals, attr_get_present_values(curr_attr)); + slapi_valueset_join_attr_valueset(curr_attr, all_vals, &curr_attr->a_present_values); } } @@ -568,7 +568,7 @@ index_add_mods( for (curr_attr = olde->ep_entry->e_attrs; curr_attr != NULL; curr_attr = curr_attr->a_next) { if (slapi_attr_type_cmp( mods[i]->mod_type, curr_attr->a_type, SLAPI_TYPE_CMP_EXACT ) == 0) { - valueset_add_valuearray(mod_vals, attr_get_present_values(curr_attr)); + slapi_valueset_join_attr_valueset(curr_attr, mod_vals, &curr_attr->a_present_values); } } @@ -586,7 +586,7 @@ index_add_mods( slapi_entry_attr_find( olde->ep_entry, mods[i]->mod_type, &curr_attr ); if ( mods_valueArray != NULL ) { for ( j = 0; mods_valueArray[j] != NULL; j++ ) { - Slapi_Value *rval = valuearray_remove_value(curr_attr, evals, mods_valueArray[j]); + Slapi_Value *rval = valueset_remove_value(curr_attr, all_vals, mods_valueArray[j]); slapi_value_free( &rval ); } } @@ -595,12 +595,12 @@ index_add_mods( * they don't exist, delete the equality index. */ for ( j = 0; deleted_valueArray[j] != NULL; j++ ) { - if (valuearray_find(curr_attr, evals, deleted_valueArray[j]) == -1) { + if ( !slapi_valueset_find(curr_attr, all_vals, deleted_valueArray[j])) { if (!(flags & BE_INDEX_EQUALITY)) { flags |= BE_INDEX_EQUALITY; } } else { - Slapi_Value *rval = valuearray_remove_value(curr_attr, deleted_valueArray, deleted_valueArray[j]); + Slapi_Value *rval = valueset_remove_value(curr_attr, mod_vals, deleted_valueArray[j]); slapi_value_free( &rval ); j--; /* indicates there was some conflict */ @@ -639,8 +639,8 @@ index_add_mods( if (curr_attr) { /* found the type */ for (j = 0; mods_valueArray[j] != NULL; j++) { /* mods_valueArray[j] is in curr_attr ==> return 0 */ - if (slapi_attr_value_find(curr_attr, - slapi_value_get_berval(mods_valueArray[j]))) { + if ( !slapi_valueset_find(curr_attr, &curr_attr->a_present_values, + mods_valueArray[j])) { /* The value is NOT in newe, remove it. */ Slapi_Value *rval; rval = valuearray_remove_value(curr_attr, @@ -678,9 +678,9 @@ index_add_mods( mod_vals = slapi_valueset_new(); for (curr_attr = olde->ep_entry->e_attrs; curr_attr != NULL; curr_attr = curr_attr->a_next) { - if (slapi_attr_type_cmp( mods[i]->mod_type, curr_attr->a_type, SLAPI_TYPE_CMP_EXACT ) == 0) { - valueset_add_valuearray(mod_vals, attr_get_present_values(curr_attr)); - } + if (slapi_attr_type_cmp( mods[i]->mod_type, curr_attr->a_type, SLAPI_TYPE_CMP_EXACT ) == 0) { + slapi_valueset_join_attr_valueset(curr_attr, mod_vals, &curr_attr->a_present_values); + } } deleted_valueArray = valueset_get_valuearray(mod_vals); @@ -696,14 +696,14 @@ index_add_mods( * also exist in a subtype. */ for (j = 0; deleted_valueArray && deleted_valueArray[j]; j++) { - if ( valuearray_find(curr_attr, evals, deleted_valueArray[j]) == -1 ) { + if ( !slapi_valueset_find(curr_attr, all_vals, deleted_valueArray[j])) { /* If the equality flag isn't already set, set it */ if (!(flags & BE_INDEX_EQUALITY)) { flags |= BE_INDEX_EQUALITY; } } else { /* Remove duplicate value from the mod list */ - Slapi_Value *rval = valuearray_remove_value(curr_attr, deleted_valueArray, deleted_valueArray[j]); + Slapi_Value *rval = valueset_remove_value(curr_attr, mod_vals, deleted_valueArray[j]); slapi_value_free( &rval ); j--; } @@ -752,7 +752,7 @@ index_add_mods( if (curr_attr) { int found = 0; for (j = 0; mods_valueArray[j] != NULL; j++ ) { - if ( valuearray_find(curr_attr, evals, mods_valueArray[j]) > -1 ) { + if ( slapi_valueset_find(curr_attr, all_vals, mods_valueArray[j])) { /* The same value found in evals. * We don't touch the equality index. */ found = 1; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c index fa18550..16ffa42 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c @@ -931,7 +931,7 @@ ldbm_compute_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_ Slapi_Attr our_attr; slapi_attr_init(&our_attr, numsubordinates); our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR; - valueset_add_string(&our_attr.a_present_values,"0",CSN_TYPE_UNKNOWN,NULL); + valueset_add_string(&our_attr, &our_attr.a_present_values,"0",CSN_TYPE_UNKNOWN,NULL); rc = (*outputfn) (c, &our_attr, e); attr_done(&our_attr); return (rc); @@ -948,9 +948,9 @@ ldbm_compute_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_ rc = slapi_entry_attr_find( e, numsubordinates, &read_attr ); if ( (0 != rc) || slapi_entry_attr_hasvalue(e,numsubordinates,"0") ) { /* If not, or present and zero, we return FALSE, otherwise TRUE */ - valueset_add_string(&our_attr.a_present_values,"FALSE",CSN_TYPE_UNKNOWN,NULL); + valueset_add_string(&our_attr, &our_attr.a_present_values,"FALSE",CSN_TYPE_UNKNOWN,NULL); } else { - valueset_add_string(&our_attr.a_present_values,"TRUE",CSN_TYPE_UNKNOWN,NULL); + valueset_add_string(&our_attr, &our_attr.a_present_values,"TRUE",CSN_TYPE_UNKNOWN,NULL); } rc = (*outputfn) (c, &our_attr, e); attr_done(&our_attr); diff --git a/ldap/servers/slapd/computed.c b/ldap/servers/slapd/computed.c index 353d375..b82e2e8 100644 --- a/ldap/servers/slapd/computed.c +++ b/ldap/servers/slapd/computed.c @@ -124,7 +124,7 @@ compute_stock_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi Slapi_Attr our_attr; slapi_attr_init(&our_attr, subschemasubentry); our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR; - valueset_add_string(&our_attr.a_present_values,SLAPD_SCHEMA_DN,CSN_TYPE_UNKNOWN,NULL); + valueset_add_string(&our_attr, &our_attr.a_present_values,SLAPD_SCHEMA_DN,CSN_TYPE_UNKNOWN,NULL); rc = (*outputfn) (c, &our_attr, e); attr_done(&our_attr); return (rc); diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c index 29fe075..8a5df7e 100644 --- a/ldap/servers/slapd/entry.c +++ b/ldap/servers/slapd/entry.c @@ -223,8 +223,6 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo ) int freeval = 0; int value_state= VALUE_NOTFOUND; int attr_state= ATTRIBUTE_NOTFOUND; - int maxvals; - int del_maxvals; if ( *s == '\n' || *s == '\0' ) { break; @@ -266,9 +264,7 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo ) slapi_ch_free_string(&ptype); ptype=PL_strndup(type.bv_val, type.bv_len); nvals = 0; - maxvals = 0; del_nvals = 0; - del_maxvals = 0; a = NULL; } @@ -484,25 +480,21 @@ str2entry_fast( const char *rawdn, char *s, int flags, int read_stateinfo ) if(value_state==VALUE_DELETED) { /* consumes the value */ - valuearray_add_value_fast( - &(*a)->a_deleted_values.va, /* JCM .va is private */ - svalue, - del_nvals, - &del_maxvals, - 0/*!Exact*/, - 1/*Passin*/ ); + slapi_valueset_add_attr_value_ext( + *a, + &(*a)->a_deleted_values, + svalue, + SLAPI_VALUE_FLAG_PASSIN ); del_nvals++; } else { /* consumes the value */ - valuearray_add_value_fast( - &(*a)->a_present_values.va, /* JCM .va is private */ - svalue, - nvals, - &maxvals, - 0 /*!Exact*/, - 1 /*Passin*/ ); + slapi_valueset_add_attr_value_ext( + *a, + &(*a)->a_present_values, + svalue, + SLAPI_VALUE_FLAG_PASSIN); nvals++; } if(attributedeletioncsn!=NULL) @@ -582,8 +574,8 @@ typedef struct _entry_attrs { typedef struct _str2entry_attr { char *sa_type; int sa_state; - struct valuearrayfast sa_present_values; - struct valuearrayfast sa_deleted_values; + struct slapi_value_set sa_present_values; + struct slapi_value_set sa_deleted_values; int sa_numdups; value_compare_fn_type sa_comparefn; Avlnode *sa_vtree; @@ -594,13 +586,13 @@ typedef struct _str2entry_attr { static void entry_attr_init(str2entry_attr *sa, const char *type, int state) { - sa->sa_type= slapi_ch_strdup(type); + sa->sa_type= slapi_ch_strdup(type); sa->sa_state= state; - valuearrayfast_init(&sa->sa_present_values,NULL); - valuearrayfast_init(&sa->sa_deleted_values,NULL); - sa->sa_numdups= 0; + slapi_valueset_init(&sa->sa_present_values); + slapi_valueset_init(&sa->sa_deleted_values); + sa->sa_numdups= 0; sa->sa_comparefn = NULL; - sa->sa_vtree= NULL; + sa->sa_vtree= NULL; sa->sa_attributedeletioncsn= NULL; slapi_attr_init(&sa->sa_attr, type); } @@ -733,28 +725,26 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) char *type; struct berval bvtype; str2entry_attr *sa; - int i, j; + int i; char *next=NULL; char *valuecharptr=NULL; struct berval bvvalue; int rc; - int fast_dup_check = 0; - entry_attrs *ea = NULL; - int tree_attr_checking = 0; - int big_entry_attr_presence_check = 0; - int check_for_duplicate_values = - ( 0 != ( flags & SLAPI_STR2ENTRY_REMOVEDUPVALS )); - Slapi_Value *value = 0; - CSN *attributedeletioncsn= NULL; - CSNSet *valuecsnset= NULL; - CSN *maxcsn= NULL; - char *normdn = NULL; - int strict = 0; + entry_attrs *ea = NULL; + int tree_attr_checking = 0; + int big_entry_attr_presence_check = 0; + int check_for_duplicate_values = (0 != (flags & SLAPI_STR2ENTRY_REMOVEDUPVALS)); + Slapi_Value *value = 0; + CSN *attributedeletioncsn= NULL; + CSNSet *valuecsnset= NULL; + CSN *maxcsn= NULL; + char *normdn = NULL; + int strict = 0; /* Check if we should be performing strict validation. */ strict = config_get_dn_validate_strict(); - LDAPDebug( LDAP_DEBUG_TRACE, "=> str2entry_dupcheck\n", 0, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "=> str2entry_dupcheck\n", 0, 0, 0 ); e = slapi_entry_alloc(); slapi_entry_init(e,NULL,NULL); @@ -977,7 +967,6 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) if ( prev_attr==NULL ) { /* Haven't seen this type yet */ - fast_dup_check = 1; if ( nattrs == maxattrs ) { /* Out of space - reallocate */ @@ -1009,15 +998,6 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) /* Get the comparison function for later use */ attr_get_value_cmp_fn( &attrs[nattrs].sa_attr, &(attrs[nattrs].sa_comparefn)); /* - * If the compare function wasn't available, - * we have to revert to AVL-tree-based dup checking, - * which uses index keys for comparisons - */ - if (NULL == attrs[nattrs].sa_comparefn) - { - fast_dup_check = 0; - } - /* * If we are maintaining the attribute tree, * then add the new attribute to the tree. */ @@ -1073,66 +1053,20 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) { /* * for deleted values, we do not want to perform a dupcheck against - * existing values. Also, we do not want to add it to the - * avl tree (if one is being maintained) - * + * existing values. */ - rc = 0; /* Presume no duplicate */ + rc = slapi_valueset_add_attr_value_ext(&sa->sa_attr, &sa->sa_deleted_values,value, SLAPI_VALUE_FLAG_PASSIN); } - else if ( !check_for_duplicate_values ) + else { - rc = LDAP_SUCCESS; /* presume no duplicate */ - } else { - /* For value dup checking, we either use brute-force, if there's a small number */ - /* Or a tree-based approach if there's a large number. */ - /* The tree code is expensive, which is why we don't use it unless there's many attributes */ - rc = 0; /* Presume no duplicate */ - if (fast_dup_check) - { - /* Fast dup-checking */ - /* Do we now have so many values that we should switch to tree-based checking ? */ - if (sa->sa_present_values.num > STR2ENTRY_VALUE_DUPCHECK_THRESHOLD) - { - /* Make the tree from the existing attr values */ - rc= valuetree_add_valuearray( &sa->sa_attr, sa->sa_present_values.va, &sa->sa_vtree, NULL); - /* Check if the value already exists, in the tree. */ - rc= valuetree_add_value( &sa->sa_attr, value, &sa->sa_vtree); - fast_dup_check = 0; - } - else - { - /* JCM - need an efficient valuearray function to do this */ - /* Brute-force check */ - for ( j = 0; j < sa->sa_present_values.num; j++ )/* JCM innards */ - { - if (0 == sa->sa_comparefn(slapi_value_get_berval(value),slapi_value_get_berval(sa->sa_present_values.va[j])))/* JCM innards */ - { - /* Oops---this value matches one already present */ - rc = LDAP_TYPE_OR_VALUE_EXISTS; - break; - } - } - } - } - else - { - /* Check if the value already exists, in the tree. */ - rc = valuetree_add_value( &sa->sa_attr, value, &sa->sa_vtree); - } + int flags = SLAPI_VALUE_FLAG_PASSIN; + if (check_for_duplicate_values) flags |= SLAPI_VALUE_FLAG_DUPCHECK; + rc = slapi_valueset_add_attr_value_ext(&sa->sa_attr, &sa->sa_present_values,value, flags); } if ( rc==LDAP_SUCCESS ) { - if(value_state==VALUE_DELETED) - { - valuearrayfast_add_value_passin(&sa->sa_deleted_values,value); - value= NULL; /* value was consumed */ - } - else - { - valuearrayfast_add_value_passin(&sa->sa_present_values,value); - value= NULL; /* value was consumed */ - } + value= NULL; /* value was consumed */ if(attributedeletioncsn!=NULL) { sa->sa_attributedeletioncsn= attributedeletioncsn; @@ -1147,7 +1081,7 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) else { /* Failure adding to value tree */ - LDAPDebug( LDAP_DEBUG_ANY, "str2entry_dupcheck: unexpected failure %d constructing value tree\n", rc, 0, 0 ); + LDAPDebug( LDAP_DEBUG_ANY, "str2entry_dupcheck: unexpected failure %d adding value\n", rc, 0, 0 ); slapi_entry_free( e ); e = NULL; goto free_and_return; } @@ -1212,27 +1146,21 @@ str2entry_dupcheck( const char *rawdn, char *s, int flags, int read_stateinfo ) } if(alist!=NULL) { - int maxvals = 0; Slapi_Attr **a= NULL; attrlist_find_or_create_locking_optional(alist, sa->sa_type, &a, PR_FALSE); - valuearray_add_valuearray_fast( /* JCM should be calling a valueset function */ - &(*a)->a_present_values.va, /* JCM .va is private */ - sa->sa_present_values.va, - 0, /* Currently there are no present values on the attribute */ - sa->sa_present_values.num, - &maxvals, - 1/*Exact*/, - 1/*Passin*/); + slapi_valueset_add_attr_valuearray_ext( + *a, + &(*a)->a_present_values, + sa->sa_present_values.va, + sa->sa_present_values.num, + SLAPI_VALUE_FLAG_PASSIN, NULL); sa->sa_present_values.num= 0; /* The values have been consumed */ - maxvals = 0; - valuearray_add_valuearray_fast( /* JCM should be calling a valueset function */ - &(*a)->a_deleted_values.va, /* JCM .va is private */ - sa->sa_deleted_values.va, - 0, /* Currently there are no deleted values on the attribute */ - sa->sa_deleted_values.num, - &maxvals, - 1/*Exact*/, - 1/*Passin*/); + slapi_valueset_add_attr_valuearray_ext( + *a, + &(*a)->a_deleted_values, + sa->sa_deleted_values.va, + sa->sa_deleted_values.num, + SLAPI_VALUE_FLAG_PASSIN, NULL); sa->sa_deleted_values.num= 0; /* The values have been consumed */ if(sa->sa_attributedeletioncsn!=NULL) { @@ -1279,9 +1207,8 @@ free_and_return: for ( i = 0; i < nattrs; i++ ) { slapi_ch_free((void **) &(attrs[ i ].sa_type)); - valuearrayfast_done(&attrs[ i ].sa_present_values); - valuearrayfast_done(&attrs[ i ].sa_deleted_values); - valuetree_free( &attrs[ i ].sa_vtree ); + slapi_ch_free((void **) &(attrs[ i ].sa_present_values.va)); + slapi_ch_free((void **) &(attrs[ i ].sa_deleted_values.va)); attr_done( &attrs[ i ].sa_attr ); } if (tree_attr_checking) @@ -2663,7 +2590,7 @@ slapi_entry_add_string(Slapi_Entry *e, const char *type, const char *value) { Slapi_Attr **a= NULL; attrlist_find_or_create(&e->e_attrs, type, &a); - valueset_add_string ( &(*a)->a_present_values, value, CSN_TYPE_UNKNOWN, NULL); + valueset_add_string ( *a, &(*a)->a_present_values, value, CSN_TYPE_UNKNOWN, NULL); return 0; } diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c index cca615d..8cee986 100644 --- a/ldap/servers/slapd/entrywsi.c +++ b/ldap/servers/slapd/entrywsi.c @@ -464,7 +464,10 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b /* Append the pending values to a->a_present_values */ valuearray_update_csn (valuestoadd,CSN_TYPE_VALUE_UPDATED,csn); - valueset_add_valuearray_ext(&a->a_present_values, valuestoadd, SLAPI_VALUE_FLAG_PASSIN); + slapi_valueset_add_attr_valuearray_ext(a, &a->a_present_values, + valuestoadd, + valuearray_count(valuestoadd), + SLAPI_VALUE_FLAG_PASSIN, NULL); slapi_ch_free ( (void **)&valuestoadd ); /* @@ -502,7 +505,10 @@ entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **b Slapi_ValueSet vs; /* Add each deleted value to the present list */ valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_UPDATED,csn); - valueset_add_valuearray_ext(&a->a_present_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN); + slapi_valueset_add_attr_valuearray_ext(a, &a->a_present_values, + deletedvalues, + valuearray_count(deletedvalues), + SLAPI_VALUE_FLAG_PASSIN, NULL); /* Remove the deleted values from the values to add */ valueset_set_valuearray_passin(&vs,valuestoadd); valueset_remove_valuearray(&vs, a, deletedvalues, SLAPI_VALUE_FLAG_IGNOREERROR, &v); @@ -583,7 +589,10 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval valueset_update_csn_for_valuearray(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated); valuearray_free(&valuesupdated); valuearray_update_csn(valuestodelete,CSN_TYPE_VALUE_DELETED,csn); - valueset_add_valuearray_ext(&a->a_deleted_values, valuestodelete, SLAPI_VALUE_FLAG_PASSIN); + slapi_valueset_add_attr_valuearray_ext(a, &a->a_deleted_values, + valuestodelete, + valuearray_count(valuestodelete), + SLAPI_VALUE_FLAG_PASSIN, NULL); /* all the elements in valuestodelete are passed; * should free valuestodelete only (don't call valuearray_free) * [622023] */ @@ -602,7 +611,10 @@ entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval /* We don't maintain a deleted value list for single valued attributes */ /* Add each deleted value to the deleted set */ valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_DELETED,csn); - valueset_add_valuearray_ext(&a->a_deleted_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN); + slapi_valueset_add_attr_valuearray_ext(a, &a->a_deleted_values, + deletedvalues, + valuearray_count(deletedvalues), + SLAPI_VALUE_FLAG_PASSIN, NULL); slapi_ch_free((void **)&deletedvalues); } else { diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 7a20bdf..954cfd2 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -166,13 +166,6 @@ int valuearray_first_value( Slapi_Value **va, Slapi_Value **v ); void valuearrayfast_init(struct valuearrayfast *vaf,Slapi_Value **va); void valuearrayfast_done(struct valuearrayfast *vaf); -void valuearrayfast_add_value(struct valuearrayfast *vaf,const Slapi_Value *v); -void valuearrayfast_add_value_passin(struct valuearrayfast *vaf,Slapi_Value *v); -void valuearrayfast_add_valuearrayfast(struct valuearrayfast *vaf,const struct valuearrayfast *vaf_add); - -int valuetree_add_value( const Slapi_Attr *sattr, const Slapi_Value *va, Avlnode **valuetreep); -int valuetree_add_valuearray( const Slapi_Attr *sattr, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index); -void valuetree_free( Avlnode **valuetreep ); /* Valueset functions */ @@ -183,15 +176,17 @@ int valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Va int valueset_purge(Slapi_ValueSet *vs, const CSN *csn); Slapi_Value **valueset_get_valuearray(const Slapi_ValueSet *vs); size_t valueset_size(const Slapi_ValueSet *vs); +void slapi_valueset_add_valuearray(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **addvals); void valueset_add_valuearray(Slapi_ValueSet *vs, Slapi_Value **addvals); void valueset_add_valuearray_ext(Slapi_ValueSet *vs, Slapi_Value **addvals, PRUint32 flags); -void valueset_add_string(Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn); +void valueset_add_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn); void valueset_update_csn(Slapi_ValueSet *vs, CSNType t, const CSN *csn); void valueset_add_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2); int valueset_intersectswith_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **values, int *duplicate_index); Slapi_ValueSet *valueset_dup(const Slapi_ValueSet *dupee); void valueset_remove_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s); -int valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **vals); +int valueset_replace_valuearray(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **vals); +int valueset_replace_valuearray_ext(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **vals, int dupcheck); void valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated); void valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals); void valueset_set_valuearray_passin(Slapi_ValueSet *vs, Slapi_Value **addvals); diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c index 258f6eb..045989d 100644 --- a/ldap/servers/slapd/schema.c +++ b/ldap/servers/slapd/schema.c @@ -4707,11 +4707,11 @@ va_locate_oc_val( Slapi_Value **va, const char *oc_name, const char *oc_oid ) * oc_unlock(); */ static void -va_expand_one_oc( const char *dn, Slapi_Value ***vap, const char *ocs ) +va_expand_one_oc( const char *dn, const Slapi_Attr *a, Slapi_ValueSet *vs, const char *ocs ) { struct objclass *this_oc, *sup_oc; - int p,i; - Slapi_Value **newva; + int p; + Slapi_Value **va = vs->va; this_oc = oc_find_nolock( ocs ); @@ -4728,29 +4728,18 @@ va_expand_one_oc( const char *dn, Slapi_Value ***vap, const char *ocs ) return; /* superior is unknown -- ignore */ } - p = va_locate_oc_val( *vap, sup_oc->oc_name, sup_oc->oc_oid ); + p = va_locate_oc_val( va, sup_oc->oc_name, sup_oc->oc_oid ); if ( p != -1 ) { return; /* value already present -- done! */ } - /* parent was not found. add to the end */ - for ( i = 0; (*vap)[i] != NULL; i++ ) { - ; - } - - /* prevent loops: stop if more than 1000 OC values are present */ - if ( i > 1000 ) { + if ( slapi_valueset_count(vs) > 1000 ) { return; } - newva = (Slapi_Value **)slapi_ch_realloc( (char *)*vap, - ( i + 2 )*sizeof(Slapi_Value *)); - - newva[i] = slapi_value_new_string(sup_oc->oc_name); - newva[i+1] = NULL; - - *vap = newva; + slapi_valueset_add_attr_value_ext(a, vs, slapi_value_new_string(sup_oc->oc_name), SLAPI_VALUE_FLAG_PASSIN); + LDAPDebug( LDAP_DEBUG_TRACE, "Entry \"%s\": added missing objectClass value %s\n", dn, sup_oc->oc_name, 0 ); @@ -4762,11 +4751,12 @@ va_expand_one_oc( const char *dn, Slapi_Value ***vap, const char *ocs ) * All missing superior classes are added to the objectClass attribute, as * is 'top' if it is missing. */ -void -slapi_schema_expand_objectclasses( Slapi_Entry *e ) +static void +schema_expand_objectclasses_ext( Slapi_Entry *e, int lock) { Slapi_Attr *sa; - Slapi_Value **va; + Slapi_Value *v; + Slapi_ValueSet *vs; const char *dn = slapi_entry_get_dn_const( e ); int i; @@ -4774,76 +4764,41 @@ slapi_schema_expand_objectclasses( Slapi_Entry *e ) return; /* no OC values -- nothing to do */ } - va = attr_get_present_values( sa ); - - if ( va == NULL || va[0] == NULL ) { + vs = &sa->a_present_values; + if ( slapi_valueset_isempty(vs) ) { return; /* no OC values -- nothing to do */ } - oc_lock_read(); + if (lock) + oc_lock_read(); /* * This loop relies on the fact that bv_expand_one_oc() * always adds to the end */ - for ( i = 0; va[i] != NULL; ++i ) { - if ( NULL != slapi_value_get_string(va[i]) ) { - va_expand_one_oc( dn, &va, slapi_value_get_string(va[i]) ); - } + i = slapi_valueset_first_value(vs,&v); + while ( v != NULL) { + if ( NULL != slapi_value_get_string(v) ) { + va_expand_one_oc( dn, sa, &sa->a_present_values, slapi_value_get_string(v) ); + } + i = slapi_valueset_next_value(vs, i, &v); } /* top must always be present */ - va_expand_one_oc( dn, &va, "top" ); - - /* - * Reset the present values in the set because we may have realloc'd it. - * Note that this is the counterpart to the attr_get_present_values() - * call we made above... nothing new has been allocated, but sa holds - * a pointer to the original (pre realloc) va. - */ - sa->a_present_values.va = va; - - oc_unlock(); + va_expand_one_oc( dn, sa, &sa->a_present_values, "top" ); + if (lock) + oc_unlock(); +} +void +slapi_schema_expand_objectclasses( Slapi_Entry *e ) +{ + schema_expand_objectclasses_ext( e, 1); } void schema_expand_objectclasses_nolock( Slapi_Entry *e ) { - Slapi_Attr *sa; - Slapi_Value **va; - const char *dn = slapi_entry_get_dn_const( e ); - int i; - - if ( 0 != slapi_entry_attr_find( e, SLAPI_ATTR_OBJECTCLASS, &sa )) { - return; /* no OC values -- nothing to do */ - } - - va = attr_get_present_values( sa ); - - if ( va == NULL || va[0] == NULL ) { - return; /* no OC values -- nothing to do */ - } - - /* - * This loop relies on the fact that bv_expand_one_oc() - * always adds to the end - */ - for ( i = 0; va[i] != NULL; ++i ) { - if ( NULL != slapi_value_get_string(va[i]) ) { - va_expand_one_oc( dn, &va, slapi_value_get_string(va[i]) ); - } - } - - /* top must always be present */ - va_expand_one_oc( dn, &va, "top" ); - - /* - * Reset the present values in the set because we may have realloc'd it. - * Note that this is the counterpart to the attr_get_present_values() - * call we made above... nothing new has been allocated, but sa holds - * a pointer to the original (pre realloc) va. - */ - sa->a_present_values.va = va; + schema_expand_objectclasses_ext( e, 0); } /* lock to protect both objectclass and schema_dse */ diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 9a05da9..2465500 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -439,8 +439,14 @@ struct slapi_value * struct slapi_value_tree *vt; * }; */ + +/* It is a useless layer, always use the valuarray fast version */ +#define VALUE_SORT_THRESHOLD 10 struct slapi_value_set { + int num; /* The number of values in the array */ + int max; /* The number of slots in the array */ + int *sorted; /* sorted array of indices, if NULL va is not sorted */ struct slapi_value **va; }; @@ -511,6 +517,8 @@ typedef struct asyntaxinfo { #define SLAPI_ATTR_FLAG_NOLOCKING 0x0020 /* the init code doesn't lock the tables */ #define SLAPI_ATTR_FLAG_KEEP 0x8000 /* keep when replacing all */ +#define SLAPI_ATTR_FLAG_SYNTAX_LOOKUP_DONE 0x010000 /* syntax lookup done, flag set */ +#define SLAPI_ATTR_FLAG_SYNTAX_IS_DN 0x020000 /* syntax lookup done, flag set */ /* This is the type of the function passed into attr_syntax_enumerate_attrs */ typedef int (*AttrEnumFunc)(struct asyntaxinfo *asi, void *arg); diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index e5fe904..304c5a8 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -4594,6 +4594,7 @@ void slapi_ber_bvcpy(struct berval *bvd, const struct berval *bvs); #define SLAPI_VALUE_FLAG_IGNOREERROR 0x2 #define SLAPI_VALUE_FLAG_PRESERVECSNSET 0x4 #define SLAPI_VALUE_FLAG_USENEWVALUE 0x8 /* see valueset_remove_valuearray */ +#define SLAPI_VALUE_FLAG_DUPCHECK 0x10 /* used in valueset_add... */ /** * Creates an empty \c Slapi_ValueSet structure. @@ -4687,7 +4688,8 @@ void slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval); * \see slapi_valueset_first_value() * \see slapi_valueset_next_value() */ -void slapi_valueset_add_value_ext(Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags); +void slapi_valueset_add_value_ext(Slapi_ValueSet *vs, const Slapi_Value *addval, unsigned long flags); +int slapi_valueset_add_attr_value_ext(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags); /** * Gets the first value in a \c Slapi_ValueSet structure. @@ -4743,6 +4745,16 @@ int slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v); int slapi_valueset_count( const Slapi_ValueSet *vs); /** + * Checks if a \c Slapi_ValueSet structure has values + * + * \param vs Pointer to the \c Slapi_ValueSet structure of which + * you wish to get the count. + * \return 1 if there are no values contained in the \c Slapi_ValueSet structure. + * \return 0 if there are values contained in the \c Slapi_ValueSet structure. + */ +int slapi_valueset_isempty( const Slapi_ValueSet *vs); + +/** * Initializes a \c Slapi_ValueSet with copies of the values of a \c Slapi_Mod structure. * * \param vs Pointer to the \c Slapi_ValueSet structure into which @@ -4773,6 +4785,7 @@ void slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod); * \see slapi_valueset_done() */ void slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2); +void slapi_valueset_join_attr_valueset(const Slapi_Attr *a, Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2); /** * Finds a requested value in a valueset. diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index 1efbc8b..8c5541a 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -833,9 +833,12 @@ int charray_normdn_add(char ***chararray, char *dn, char *errstr); * the very least before we make them public. */ void valuearray_add_value(Slapi_Value ***vals, const Slapi_Value *addval); -void valuearray_add_value_fast(Slapi_Value ***vals, Slapi_Value *addval, int nvals, int *maxvals, int exact, int passin); void valuearray_add_valuearray( Slapi_Value ***vals, Slapi_Value **addvals, PRUint32 flags ); void valuearray_add_valuearray_fast( Slapi_Value ***vals, Slapi_Value **addvals, int nvals, int naddvals, int *maxvals, int exact, int passin ); +Slapi_Value * valueset_find_sorted (const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v, int *index); +int valueset_insert_value_to_sorted(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value *vi, int dupcheck); +void valueset_array_to_sorted (const Slapi_Attr *a, Slapi_ValueSet *vs); +int slapi_valueset_add_attr_valuearray_ext(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **addval, int nvals, unsigned long flags, int *dup_index); int valuearray_find(const Slapi_Attr *a, Slapi_Value **va, const Slapi_Value *v); int valuearray_dn_normalize_value(Slapi_Value **vals); diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c index 732b411..4ee2938 100644 --- a/ldap/servers/slapd/valueset.c +++ b/ldap/servers/slapd/valueset.c @@ -469,7 +469,8 @@ valuearray_purge(Slapi_Value ***va, const CSN *csn) *va= NULL; } - return(0); + /* return the number of remaining values */ + return(i); } size_t @@ -498,51 +499,6 @@ valuearray_update_csn(Slapi_Value **va, CSNType t, const CSN *csn) } } -/* - * Shunt up the values to cover the empty slots. - * - * "compressed" means "contains no NULL's" - * - * Invariant for the outer loop: - * va[0..i] is compressed && - * va[n..numvalues] contains just NULL's - * - * Invariant for the inner loop: - * i */ void @@ -583,237 +539,11 @@ valuearrayfast_add_value_passin(struct valuearrayfast *vaf,Slapi_Value *v) vaf->num++; } -void -valuearrayfast_add_valuearrayfast(struct valuearrayfast *vaf,const struct valuearrayfast *vaf_add) -{ - valuearray_add_valuearray_fast(&vaf->va,vaf_add->va,vaf->num,vaf_add->num,&vaf->max,0/*Exact*/,0/*!PassIn*/); - vaf->num+= vaf_add->num; -} - -/* <=========================== ValueArrayIndexTree =======================> */ - -static int valuetree_dupvalue_disallow( caddr_t d1, caddr_t d2 ); -static int valuetree_node_cmp( caddr_t d1, caddr_t d2 ); -static int valuetree_node_free( caddr_t data ); - -/* - * structure used within AVL value trees. - */ -typedef struct valuetree_node -{ - int index; /* index into the value array */ - Slapi_Value *sval; /* the actual value */ -} valuetree_node; - -/* - * Create or update an AVL tree of values that can be used to speed up value - * lookups. We store the index keys for the values in the AVL tree so - * we can use a trivial comparison function. - * - * Returns: - * LDAP_SUCCESS on success, - * LDAP_TYPE_OR_VALUE_EXISTS if the value already exists, - * LDAP_OPERATIONS_ERROR for some unexpected failure. - * - * Sets *valuetreep to the root of the AVL tree that was created. If a - * non-zero value is returned, the tree is freed if free_on_error is non-zero - * and *valuetreep is set to NULL. - */ -int -valuetree_add_valuearray( const Slapi_Attr *sattr, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index ) -{ - int rc= LDAP_SUCCESS; - - PR_ASSERT(sattr!=NULL); - PR_ASSERT(valuetreep!=NULL); - - if ( duplicate_index ) { - *duplicate_index = -1; - } - - if ( !valuearray_isempty(va) ) - { - Slapi_Value **keyvals; - /* Convert the value array into key values */ - if ( slapi_attr_values2keys_sv( sattr, (Slapi_Value**)va, &keyvals, LDAP_FILTER_EQUALITY ) != 0 ) /* jcm cast */ - { - LDAPDebug( LDAP_DEBUG_ANY,"slapi_attr_values2keys_sv for attribute %s failed\n", sattr->a_type, 0, 0 ); - rc= LDAP_OPERATIONS_ERROR; - } - else - { - int i; - valuetree_node *vaip; - for ( i = 0; rc==LDAP_SUCCESS && va[i] != NULL; ++i ) - { - if ( keyvals[i] == NULL ) - { - LDAPDebug( LDAP_DEBUG_ANY,"slapi_attr_values2keys_sv for attribute %s did not return enough key values\n", sattr->a_type, 0, 0 ); - rc= LDAP_OPERATIONS_ERROR; - } - else - { - vaip = (valuetree_node *)slapi_ch_malloc( sizeof( valuetree_node )); - vaip->index = i; - vaip->sval = keyvals[i]; - if (( rc = avl_insert( valuetreep, vaip, valuetree_node_cmp, valuetree_dupvalue_disallow )) != 0 ) - { - slapi_ch_free( (void **)&vaip ); - /* Value must already be in there */ - rc= LDAP_TYPE_OR_VALUE_EXISTS; - if ( duplicate_index ) { - *duplicate_index = i; - } - } - else - { - keyvals[i]= NULL; - } - } - } - /* start freeing at index i - the rest of them have already - been moved into valuetreep - the loop iteration will always do the +1, so we have - to remove it if so */ - i = (i > 0) ? i-1 : 0; - valuearray_free_ext( &keyvals, i ); - } - } - if(rc!=0) - { - valuetree_free( valuetreep ); - } - - return rc; -} - -int -valuetree_add_value( const Slapi_Attr *sattr, const Slapi_Value *v, Avlnode **valuetreep) -{ - Slapi_Value *va[2]; - va[0]= (Slapi_Value*)v; - va[1]= NULL; - return valuetree_add_valuearray( sattr, va, valuetreep, NULL); -} - - -/* - * - * Find value "v" using AVL tree "valuetree" - * - * returns LDAP_SUCCESS if "v" was found, LDAP_NO_SUCH_ATTRIBUTE - * if "v" was not found and LDAP_OPERATIONS_ERROR if some unexpected error occurs. - */ -static int -valuetree_find( const struct slapi_attr *a, const Slapi_Value *v, Avlnode *valuetree, int *index) -{ - const Slapi_Value *oneval[2]; - Slapi_Value **keyvals; - valuetree_node *vaip, tmpvain; - - PR_ASSERT(a!=NULL); - PR_ASSERT(a->a_plugin!=NULL); - PR_ASSERT(v!=NULL); - PR_ASSERT(valuetree!=NULL); - PR_ASSERT(index!=NULL); - - if ( a == NULL || v == NULL || valuetree == NULL ) - { - return( LDAP_OPERATIONS_ERROR ); - } - - keyvals = NULL; - oneval[0] = v; - oneval[1] = NULL; - if ( slapi_attr_values2keys_sv( a, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 /* jcm cast */ - || keyvals == NULL - || keyvals[0] == NULL ) - { - LDAPDebug( LDAP_DEBUG_ANY, "valuetree_find_and_replace: " - "slapi_attr_values2keys_sv failed for type %s\n", - a->a_type, 0, 0 ); - return( LDAP_OPERATIONS_ERROR ); - } - - tmpvain.index = 0; - tmpvain.sval = keyvals[0]; - vaip = (valuetree_node *)avl_find( valuetree, &tmpvain, valuetree_node_cmp ); - - if ( keyvals != NULL ) - { - valuearray_free( &keyvals ); - } - - if (vaip == NULL) - { - return( LDAP_NO_SUCH_ATTRIBUTE ); - } - else - { - *index= vaip->index; - } - - return( LDAP_SUCCESS ); -} - -static int -valuetree_dupvalue_disallow( caddr_t d1, caddr_t d2 ) -{ - return( 1 ); -} - - -void -valuetree_free( Avlnode **valuetreep ) -{ - if ( valuetreep != NULL && *valuetreep != NULL ) - { - avl_free( *valuetreep, valuetree_node_free ); - *valuetreep = NULL; - } -} - - -static int -valuetree_node_free( caddr_t data ) -{ - if ( data!=NULL ) - { - valuetree_node *vaip = (valuetree_node *)data; - - slapi_value_free(&vaip->sval); - slapi_ch_free( (void **)&data ); - } - return( 0 ); -} - - -static int -valuetree_node_cmp( caddr_t d1, caddr_t d2 ) -{ - const struct berval *bv1, *bv2; - int rc; - - bv1 = slapi_value_get_berval(((valuetree_node *)d1)->sval); - bv2 = slapi_value_get_berval(((valuetree_node *)d2)->sval); - - if ( bv1->bv_len < bv2->bv_len ) { - rc = -1; - } else if ( bv1->bv_len > bv2->bv_len ) { - rc = 1; - } else { - rc = memcmp( bv1->bv_val, bv2->bv_val, bv1->bv_len ); - } - - return( rc ); -} - /* <=========================== Value Set =======================> */ -/* - * JCM: All of these valueset functions are just forwarded to the - * JCM: valuearray functions... waste of time. Inline them! - */ +#define VALUESET_ARRAY_SORT_THRESHOLD 10 +#define VALUESET_ARRAY_MINSIZE 2 +#define VALUESET_ARRAY_MAXINCREMENT 4096 Slapi_ValueSet * slapi_valueset_new() @@ -832,6 +562,9 @@ slapi_valueset_init(Slapi_ValueSet *vs) if(vs!=NULL) { vs->va= NULL; + vs->sorted = NULL; + vs->num = 0; + vs->max = 0; } } @@ -845,6 +578,13 @@ slapi_valueset_done(Slapi_ValueSet *vs) valuearray_free(&vs->va); vs->va= NULL; } + if (vs->sorted != NULL) + { + slapi_ch_free ((void **)&vs->sorted); + vs->sorted = NULL; + } + vs->num = 0; + vs->max = 0; } } @@ -869,8 +609,22 @@ slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod) void valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals) { - slapi_valueset_init(vs); - valueset_add_valuearray(vs,addvals); + int i, j=0; + slapi_valueset_init(vs); + vs->num = valuearray_count(addvals); + vs->max = vs->num + 1; + vs->va = (Slapi_Value **) slapi_ch_malloc( vs->max * sizeof(Slapi_Value *)); + for ( i = 0, j = 0; i < vs->num; i++) + { + if ( addvals[i]!=NULL ) + { + /* We copy the values */ + vs->va[j] = slapi_value_dup(addvals[i]); + j++; + } + } + vs->va[j] = NULL; + } void @@ -878,6 +632,8 @@ valueset_set_valuearray_passin(Slapi_ValueSet *vs, Slapi_Value **addvals) { slapi_valueset_init(vs); vs->va= addvals; + vs->num = valuearray_count(addvals); + vs->max = vs->num + 1; } void @@ -887,6 +643,15 @@ slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2) valueset_add_valueset(vs1,vs2); } +void +slapi_valueset_join_attr_valueset(const Slapi_Attr *a, Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2) +{ + if (slapi_valueset_isempty(vs1)) + valueset_add_valueset(vs1,vs2); + else + slapi_valueset_add_attr_valuearray_ext (a, vs1, vs2->va, vs2->num, 0, NULL); +} + int slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v ) { @@ -914,21 +679,21 @@ slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v) int slapi_valueset_count( const Slapi_ValueSet *vs) { - int r=0; if (NULL != vs) { - if(!valuearray_isempty(vs->va)) - { - r= valuearray_count(vs->va); - } + return (vs->num); } - return r; + return 0; } int -slapi_valueset_isempty(const Slapi_ValueSet *vs) +slapi_valueset_isempty( const Slapi_ValueSet *vs) { - return valueset_isempty(vs); + if (NULL != vs) + { + return (vs->num == 0); + } + return 1; } int @@ -945,12 +710,14 @@ Slapi_Value * slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v) { Slapi_Value *r= NULL; - if(vs && !valuearray_isempty(vs->va)) - { - int i= valuearray_find(a,vs->va,v); - if(i!=-1) - { - r= vs->va[i]; + if(vs->num > 0) { + if (vs->sorted) { + r = valueset_find_sorted(a,vs,v,NULL); + } else { + int i= valuearray_find(a,vs->va,v); + if(i!=-1) { + r= vs->va[i]; + } } } return r; @@ -959,17 +726,46 @@ slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_V /* * The value is found in the set, removed and returned. * The caller is responsible for freeing the value. + * + * The _sorted function also handles the cleanup of the sorted array */ Slapi_Value * -valueset_remove_value(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v) +valueset_remove_value_sorted(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v) { Slapi_Value *r= NULL; - if(!valuearray_isempty(vs->va)) - { - r= valuearray_remove_value(a, vs->va, v); + int i, position = 0; + r = valueset_find_sorted(a,vs,v,&position); + if (r) { + /* the value was found, remove from valuearray */ + int index = vs->sorted[position]; + memmove(&vs->sorted[position],&vs->sorted[position+1],(vs->num - position)*sizeof(int)); + memmove(&vs->va[index],&vs->va[index+1],(vs->num - index)*sizeof(Slapi_Value *)); + vs->num--; + /* unfortunately the references in the sorted array + * to values past the removed one are no longer correct + * need to adjust */ + for (i=0; i < vs->num; i++) { + if (vs->sorted[i] > index) vs->sorted[i]--; + } } return r; } +Slapi_Value * +valueset_remove_value(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v) +{ + if (vs->sorted) { + return (valueset_remove_value_sorted(a, vs, v)); + } else { + Slapi_Value *r= NULL; + if(!valuearray_isempty(vs->va)) + { + r= valuearray_remove_value(a, vs->va, v); + if (r) + vs->num--; + } + return r; + } +} /* * Remove any values older than the CSN. @@ -978,11 +774,25 @@ int valueset_purge(Slapi_ValueSet *vs, const CSN *csn) { int r= 0; - if(!valuearray_isempty(vs->va)) - { + if(!valuearray_isempty(vs->va)) { + /* valuearray_purge is not valueset and sorting aware, + * maybe need to rewrite, at least keep the valueset + * consistent + */ r= valuearray_purge(&vs->va, csn); + vs->num = r; + if (vs->va == NULL) { + /* va was freed */ + vs->max = 0; + } + /* we can no longer rely on the sorting */ + if (vs->sorted != NULL) + { + slapi_ch_free ((void **)&vs->sorted); + vs->sorted = NULL; + } } - return r; + return 0; } Slapi_Value ** @@ -1005,11 +815,20 @@ valueset_size(const Slapi_ValueSet *vs) * The value array is passed in by value. */ void +slapi_valueset_add_valuearray(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **addvals) +{ + if(!valuearray_isempty(addvals)) + { + slapi_valueset_add_attr_valuearray_ext (a, vs, addvals, valuearray_count(addvals), 0, NULL); + } +} + +void valueset_add_valuearray(Slapi_ValueSet *vs, Slapi_Value **addvals) { if(!valuearray_isempty(addvals)) { - valuearray_add_valuearray(&vs->va, addvals, 0); + slapi_valueset_add_attr_valuearray_ext (NULL, vs, addvals, valuearray_count(addvals), 0, NULL); } } @@ -1018,7 +837,7 @@ valueset_add_valuearray_ext(Slapi_ValueSet *vs, Slapi_Value **addvals, PRUint32 { if(!valuearray_isempty(addvals)) { - valuearray_add_valuearray(&vs->va, addvals, flags); + slapi_valueset_add_attr_valuearray_ext (NULL, vs, addvals, valuearray_count(addvals), flags, NULL); } } @@ -1028,28 +847,281 @@ valueset_add_valuearray_ext(Slapi_ValueSet *vs, Slapi_Value **addvals, PRUint32 void slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval) { - valuearray_add_value(&vs->va,addval); + slapi_valueset_add_value_ext(vs, addval, 0); +} + +void +slapi_valueset_add_value_ext(Slapi_ValueSet *vs, const Slapi_Value *addval, unsigned long flags) +{ + Slapi_Value *oneval[2]; + oneval[0]= (Slapi_Value*)addval; + oneval[1]= NULL; + slapi_valueset_add_attr_valuearray_ext(NULL, vs, oneval, 1, flags, NULL); +} + + +/* find value v in the sorted array of values, using syntax of attribut a for comparison + * + */ +static int +valueset_value_syntax_cmp( const Slapi_Attr *a, const Slapi_Value *v1, const Slapi_Value *v2 ) +{ + /* this looks like a huge overhead, but there are no simple functions to normalize and + * compare available + */ + const Slapi_Value *oneval[3]; + Slapi_Value **keyvals; + int rc = -1; + + keyvals = NULL; + oneval[0] = v1; + oneval[1] = v2; + oneval[2] = NULL; + if ( slapi_attr_values2keys_sv( a, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 + || keyvals == NULL + || keyvals[0] == NULL || keyvals[1] == NULL) + { + /* this should never happen since always a syntax plugin to + * generate the keys will be found (there exists a default plugin) + * log an error and continue. + */ + LDAPDebug( LDAP_DEBUG_ANY, "valueset_value_syntax_cmp: " + "slapi_attr_values2keys_sv failed for type %s\n", + a->a_type, 0, 0 ); + } else { + struct berval *bv1, *bv2; + bv1 = &keyvals[0]->bv; + bv2 = &keyvals[1]->bv; + if ( bv1->bv_len < bv2->bv_len ) { + rc = -1; + } else if ( bv1->bv_len > bv2->bv_len ) { + rc = 1; + } else { + rc = memcmp( bv1->bv_val, bv2->bv_val, bv1->bv_len ); + } + } + if (keyvals != NULL) + valuearray_free( &keyvals ); + return (rc); + +} +static int +valueset_value_cmp( const Slapi_Attr *a, const Slapi_Value *v1, const Slapi_Value *v2 ) +{ + + if ( a == NULL || slapi_attr_is_dn_syntax_attr((Slapi_Attr *)a)) { + /* if no attr is provided just do a utf8compare */ + /* for all the values the first step of normalization is done, + * case folding still needs to be done + */ + /* would this be enough ?: return (strcasecmp(v1->bv.bv_val, v2->bv.bv_val)); */ + return (slapi_utf8casecmp((unsigned char*)v1->bv.bv_val, (unsigned char*)v2->bv.bv_val)); + } else { + /* slapi_value_compare doesn't work, it only returns 0 or -1 + return (slapi_value_compare(a, v1, v2)); + * use special compare, base on what valuetree_find did + */ + return(valueset_value_syntax_cmp(a, v1, v2)); + } +} +/* find a value in the sorted valuearray. + * If the value is found the pointer to the value is returned and if index is provided + * it will return the index of the value in the valuearray + * If the value is not found, index will contain the place where the value would be inserted + */ +Slapi_Value * +valueset_find_sorted (const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v, int *index) +{ + int cmp = -1; + int bot = -1; + int top; + + if (vs->num == 0) { + /* empty valueset */ + if (index) *index = 0; + return (NULL); + } else { + top = vs->num; + } + while (top - bot > 1) { + int mid = (top + bot)/2; + if ( (cmp = valueset_value_cmp(a, v, vs->va[vs->sorted[mid]])) > 0) + bot = mid; + else + top = mid; + } + if (index) *index = top; + /* check if the value is found */ + if ( top < vs->num && (0 == valueset_value_cmp(a, v, vs->va[vs->sorted[top]]))) + return (vs->va[vs->sorted[top]]); + else + return (NULL); } void -slapi_valueset_add_value_ext(Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags) +valueset_array_to_sorted (const Slapi_Attr *a, Slapi_ValueSet *vs) +{ + int i, j, swap; + + /* initialize sort array */ + for (i = 0; i < vs->num; i++) + vs->sorted[i] = i; + + /* now sort it, use a simple insertion sort as the array will always + * be very small when initially sorted + */ + for (i = 1; i < vs->num; i++) { + swap = vs->sorted[i]; + j = i -1; + + while ( j >= 0 && valueset_value_cmp (a, vs->va[vs->sorted[j]], vs->va[swap]) > 0 ) { + vs->sorted[j+1] = vs->sorted[j]; + j--; + } + vs->sorted[j+1] = swap; + } +} +/* insert a value into a sorted array, if dupcheck is set no duplicate values will be accepted + * (is there a reason to allow duplicates ? LK + * if the value is inserted the the function returns the index where it was inserted + * if the value already exists -index is returned to indicate anerror an the index of the existing value + */ +int +valueset_insert_value_to_sorted(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value *vi, int dupcheck) +{ + int index = -1; + Slapi_Value *v; + /* test for pre sorted array and to avoid boundary condition */ + if (vs->num == 0) { + vs->sorted[0] = 0; + vs->num++; + return(0); + } else if (valueset_value_cmp (a, vi, vs->va[vs->sorted[vs->num-1]]) > 0 ) { + vs->sorted[vs->num] = vs->num; + vs->num++; + return (vs->num); + } + v = valueset_find_sorted (a, vs, vi, &index); + if (v && dupcheck) { + /* value already exists, do not insert duplicates */ + return (-1); + } else { + memmove(&vs->sorted[index+1],&vs->sorted[index],(vs->num - index)* sizeof(int)); + vs->sorted[index] = vs->num; + vs->num++; + return(index); + } + +} + +int +slapi_valueset_add_attr_valuearray_ext(const Slapi_Attr *a, Slapi_ValueSet *vs, + Slapi_Value **addvals, int naddvals, unsigned long flags, int *dup_index) +{ + int rc = LDAP_SUCCESS; + int i, dup; + int allocate = 0; + int need; + int passin = flags & SLAPI_VALUE_FLAG_PASSIN; + int dupcheck = flags & SLAPI_VALUE_FLAG_DUPCHECK; + + if (naddvals == 0) + return (rc); + + need = vs->num + naddvals + 1; + if (need > vs->max) { + /* Expand the array */ + allocate= vs->max; + if ( allocate == 0 ) /* initial allocation */ + allocate = VALUESET_ARRAY_MINSIZE; + while ( allocate < need ) + { + if (allocate > VALUESET_ARRAY_MAXINCREMENT ) + /* do not grow exponentially */ + allocate += VALUESET_ARRAY_MAXINCREMENT; + else + allocate *= 2; + + } + } + if(allocate>0) + { + if(vs->va==NULL) + { + vs->va = (Slapi_Value **) slapi_ch_malloc( allocate * sizeof(Slapi_Value *)); + } + else + { + vs->va = (Slapi_Value **) slapi_ch_realloc( (char *) vs->va, allocate * sizeof(Slapi_Value *)); + if (vs->sorted) { + vs->sorted = (int *) slapi_ch_realloc( (char *) vs->sorted, allocate * sizeof(int)); + } + } + vs->max= allocate; + } + + if ( (vs->num + naddvals > VALUESET_ARRAY_SORT_THRESHOLD || dupcheck ) && + !vs->sorted ) { + /* initialize sort array and do initial sort */ + vs->sorted = (int *) slapi_ch_malloc( vs->max* sizeof(int)); + valueset_array_to_sorted (a, vs); + } + + for ( i = 0; i < naddvals; i++) + { + if ( addvals[i]!=NULL ) + { + if(passin) + { + /* We consume the values */ + (vs->va)[vs->num] = addvals[i]; + } + else + { + /* We copy the values */ + (vs->va)[vs->num] = slapi_value_dup(addvals[i]); + } + if (vs->sorted) { + dup = valueset_insert_value_to_sorted(a, vs, (vs->va)[vs->num], dupcheck); + if (dup < 0 ) { + rc = LDAP_TYPE_OR_VALUE_EXISTS; + if (dup_index) *dup_index = i; + if ( !passin) + slapi_value_free(&(vs->va)[vs->num]); + break; + } + } else { + vs->num++; + } + } + } + (vs->va)[vs->num] = NULL; + + return (rc); +} + +int +slapi_valueset_add_attr_value_ext(const Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags) { + Slapi_Value *oneval[2]; + int rc; oneval[0]= (Slapi_Value*)addval; oneval[1]= NULL; - valuearray_add_valuearray(&vs->va, oneval, flags); + rc = slapi_valueset_add_attr_valuearray_ext(a, vs, oneval, 1, flags, NULL ); + return (rc); } /* * The string is passed in by value. */ void -valueset_add_string(Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn) +valueset_add_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn) { Slapi_Value v; value_init(&v,NULL,t,csn); slapi_value_set_string(&v,s); - valuearray_add_value(&vs->va,&v); + slapi_valueset_add_attr_value_ext(a, vs, &v, 0 ); value_done(&v); } @@ -1059,8 +1131,30 @@ valueset_add_string(Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn void valueset_add_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2) { - if (vs1 && vs2) - valueset_add_valuearray(vs1, vs2->va); + int i; + + if (vs1 && vs2) { + if (vs2->va) { + /* need to copy valuearray */ + if (vs2->max == 0) { + /* temporary hack, not all valuesets were created properly. fix it now */ + vs1->num = valuearray_count(vs2->va); + vs1->max = vs1->num + 1; + } else { + vs1->num = vs2->num; + vs1->max = vs2->max; + } + vs1->va = (Slapi_Value **) slapi_ch_malloc( vs1->max * sizeof(Slapi_Value *)); + for (i=0; i< vs1->num;i++) { + vs1->va[i] = slapi_value_dup(vs2->va[i]); + } + vs1->va[vs1->num] = NULL; + } + if (vs2->sorted) { + vs1->sorted = (int *) slapi_ch_malloc( vs1->max* sizeof(int)); + memcpy(&vs1->sorted[0],&vs2->sorted[0],vs1->num* sizeof(int)); + } + } } void @@ -1070,7 +1164,7 @@ valueset_remove_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s) Slapi_Value *removed; value_init(&v,NULL,CSN_TYPE_NONE,NULL); slapi_value_set_string(&v,s); - removed = valuearray_remove_value(a, vs->va, &v); + removed = valueset_remove_value(a, vs, &v); if(removed) { slapi_value_free(&removed); } @@ -1109,158 +1203,59 @@ int valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestodelete, int flags, Slapi_Value ***va_out) { int rc= LDAP_SUCCESS; - if(!valuearray_isempty(vs->va)) + if(vs->num > 0) { - int numberofvaluestodelete= valuearray_count(valuestodelete); + int i; struct valuearrayfast vaf_out; + if ( va_out ) { valuearrayfast_init(&vaf_out,*va_out); } /* - * If there are more then one values, build an AVL tree to check - * the duplicated values. + * For larger valuesets the valuarray is sorted, values can be deleted individually + * */ - if ( numberofvaluestodelete > 1 ) + for ( i = 0; rc==LDAP_SUCCESS && valuestodelete[i] != NULL; ++i ) { - /* - * Several values to delete: first build an AVL tree that - * holds all of the existing values and use that to find - * the values we want to delete. - */ - Avlnode *vtree = NULL; - int numberofexistingvalues= slapi_valueset_count(vs); - rc= valuetree_add_valuearray( a, vs->va, &vtree, NULL ); - if ( rc!=LDAP_SUCCESS ) - { - /* - * failed while constructing AVL tree of existing - * values... something bad happened. - */ - rc= LDAP_OPERATIONS_ERROR; - } - else + Slapi_Value *found = valueset_remove_value(a, vs, valuestodelete[i]); + if(found!=NULL) { - int i; - /* - * find and mark all the values that are to be deleted - */ - for ( i = 0; rc == LDAP_SUCCESS && valuestodelete[i] != NULL; ++i ) + if ( va_out ) { - int index= 0; - rc = valuetree_find( a, valuestodelete[i], vtree, &index ); - if(rc==LDAP_SUCCESS) - { - if(vs->va[index]!=NULL) - { - /* Move the value to be removed to the out array */ - if ( va_out ) - { - if (vs->va[index]->v_csnset && - (flags & (SLAPI_VALUE_FLAG_PRESERVECSNSET| - SLAPI_VALUE_FLAG_USENEWVALUE))) - { - valuestodelete[i]->v_csnset = csnset_dup (vs->va[index]->v_csnset); - } - if (flags & SLAPI_VALUE_FLAG_USENEWVALUE) - { - valuearrayfast_add_value_passin(&vaf_out,valuestodelete[i]); - valuestodelete[i] = vs->va[index]; - vs->va[index] = NULL; - } - else - { - valuearrayfast_add_value_passin(&vaf_out,vs->va[index]); - vs->va[index] = NULL; - } - } - else - { - if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET) - { - valuestodelete[i]->v_csnset = vs->va[index]->v_csnset; - vs->va[index]->v_csnset = NULL; - } - slapi_value_free ( & vs->va[index] ); - } - } - else - { - /* We already deleted this value... */ - if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0) - { - /* ...that's an error. */ - rc= LDAP_NO_SUCH_ATTRIBUTE; - } - } - } - else + if (found->v_csnset && + (flags & (SLAPI_VALUE_FLAG_PRESERVECSNSET| + SLAPI_VALUE_FLAG_USENEWVALUE))) { - /* Couldn't find the value to be deleted */ - if(rc==LDAP_NO_SUCH_ATTRIBUTE && (flags & SLAPI_VALUE_FLAG_IGNOREERROR )) - { - rc= LDAP_SUCCESS; - } + valuestodelete[i]->v_csnset = csnset_dup (found->v_csnset); } - } - valuetree_free( &vtree ); - - if ( rc != LDAP_SUCCESS ) - { - LDAPDebug( LDAP_DEBUG_ANY,"could not find value %d for attr %s (%s)\n", i-1, a->a_type, ldap_err2string( rc )); - } - else - { - /* Shunt up all the remaining values to cover the deleted ones. */ - valuearray_compress(vs->va,numberofexistingvalues); - } - } - } - else - { - /* We delete one or no value, so we use brute force. */ - int i; - for ( i = 0; rc==LDAP_SUCCESS && valuestodelete[i] != NULL; ++i ) - { - Slapi_Value *found= valueset_remove_value(a, vs, valuestodelete[i]); - if(found!=NULL) - { - if ( va_out ) + if (flags & SLAPI_VALUE_FLAG_USENEWVALUE) { - if (found->v_csnset && - (flags & (SLAPI_VALUE_FLAG_PRESERVECSNSET| - SLAPI_VALUE_FLAG_USENEWVALUE))) - { - valuestodelete[i]->v_csnset = csnset_dup (found->v_csnset); - } - if (flags & SLAPI_VALUE_FLAG_USENEWVALUE) - { - valuearrayfast_add_value_passin(&vaf_out,valuestodelete[i]); - valuestodelete[i] = found; - } - else - { - valuearrayfast_add_value_passin(&vaf_out,found); - } + valuearrayfast_add_value_passin(&vaf_out,valuestodelete[i]); + valuestodelete[i] = found; } else { - if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET) - { - valuestodelete[i]->v_csnset = found->v_csnset; - found->v_csnset = NULL; - } - slapi_value_free ( & found ); + valuearrayfast_add_value_passin(&vaf_out,found); } } else { - if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0) + if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET) { - LDAPDebug( LDAP_DEBUG_ARGS,"could not find value %d for attr %s\n", i-1, a->a_type, 0 ); - rc= LDAP_NO_SUCH_ATTRIBUTE; + valuestodelete[i]->v_csnset = found->v_csnset; + found->v_csnset = NULL; } + slapi_value_free ( & found ); + } + } + else + { + if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0) + { + LDAPDebug( LDAP_DEBUG_ARGS,"could not find value %d for attr %s\n", i-1, a->a_type, 0 ); + rc= LDAP_NO_SUCH_ATTRIBUTE; } } } @@ -1276,88 +1271,13 @@ valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value return rc; } -/* - * Check if the set of values in the valueset and the valuearray intersect. - * - * Returns - * LDAP_SUCCESS - No intersection. - * LDAP_NO_SUCH_ATTRIBUTE - There is an intersection. - * LDAP_OPERATIONS_ERROR - There are duplicate values in the value set already. - */ -int -valueset_intersectswith_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **values, int *duplicate_index ) -{ - int rc= LDAP_SUCCESS; - - if ( duplicate_index ) { - *duplicate_index = -1; - } - - if(valuearray_isempty(vs->va)) - { - /* No intersection */ - } - else - { - int numberofvalues= valuearray_count(values); - /* - * determine whether we should use an AVL tree of values or not - */ - if (numberofvalues==0) - { - /* No intersection */ - } - else if ( numberofvalues > 1 ) - { - /* - * Several values to add: use an AVL tree to detect duplicates. - */ - Avlnode *vtree = NULL; - rc= valuetree_add_valuearray( a, vs->va, &vtree, duplicate_index ); - if(rc==LDAP_OPERATIONS_ERROR) - { - /* There were already duplicate values in the value set */ - } - else - { - rc= valuetree_add_valuearray( a, values, &vtree, duplicate_index ); - /* - * Returns LDAP_OPERATIONS_ERROR if something very bad happens. - * Or LDAP_TYPE_OR_VALUE_EXISTS if a value already exists. - */ - } - valuetree_free( &vtree ); - } - else - { - /* - * One value to add: don't bother constructing - * an AVL tree, etc. since it probably isn't worth the time. - * - * JCM - This is actually quite slow because the comparison function is looked up many times. - */ - int i; - for ( i = 0; rc == LDAP_SUCCESS && values[i] != NULL; ++i ) - { - if(valuearray_find(a, vs->va, values[i])!=-1) - { - rc = LDAP_TYPE_OR_VALUE_EXISTS; - *duplicate_index = i; - break; - } - } - } - } - return rc; -} - Slapi_ValueSet * valueset_dup(const Slapi_ValueSet *dupee) { - Slapi_ValueSet *duped= (Slapi_ValueSet *)slapi_ch_calloc(1,sizeof(Slapi_ValueSet)); + Slapi_ValueSet *duped = slapi_valueset_new(); if (NULL!=duped) { - valueset_add_valuearray( duped, dupee->va ); + valueset_set_valuearray_byval(duped,dupee->va); } return duped; } @@ -1369,43 +1289,53 @@ valueset_dup(const Slapi_ValueSet *dupee) * : LDAP_OPERATIONS_ERROR - duplicated values given */ int -valueset_replace(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace) +valueset_replace_valuearray(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace) +{ + return (valueset_replace_valuearray_ext(a, vs,valstoreplace, 1)); +} +int +valueset_replace_valuearray_ext(Slapi_Attr *a, Slapi_ValueSet *vs, Slapi_Value **valstoreplace, int dupcheck) { int rc = LDAP_SUCCESS; - int numberofvalstoreplace= valuearray_count(valstoreplace); - /* verify the given values are not duplicated. - if replacing with one value, no need to check. just replace it. - */ - if (numberofvalstoreplace > 1) - { - Avlnode *vtree = NULL; - rc = valuetree_add_valuearray( a, valstoreplace, &vtree, NULL ); - valuetree_free(&vtree); - if ( LDAP_SUCCESS != rc && - /* bz 247413: don't override LDAP_TYPE_OR_VALUE_EXISTS */ - LDAP_TYPE_OR_VALUE_EXISTS != rc ) - { - /* There were already duplicate values in the value set */ - rc = LDAP_OPERATIONS_ERROR; - } - } - - if ( rc == LDAP_SUCCESS ) - { - /* values look good - replace the values in the attribute */ - if(!valuearray_isempty(vs->va)) - { - /* remove old values */ - slapi_valueset_done(vs); - } - /* we now own valstoreplace */ - vs->va = valstoreplace; - } - else - { - /* caller expects us to own valstoreplace - since we cannot - use them, just delete them */ - valuearray_free(&valstoreplace); + int vals_count = valuearray_count(valstoreplace); + + if (vals_count == 0) { + /* no new values, just clear the valueset */ + slapi_valueset_done(vs); + } else if (vals_count == 1 || !dupcheck) { + /* just repelace the valuearray and adjus num, max */ + slapi_valueset_done(vs); + vs->va = valstoreplace; + vs->num = vals_count; + vs->max = vals_count + 1; + } else { + /* verify the given values are not duplicated. */ + Slapi_ValueSet *vs_new = slapi_valueset_new(); + rc = slapi_valueset_add_attr_valuearray_ext (a, vs_new, valstoreplace, vals_count, 0, NULL); + + if ( rc == LDAP_SUCCESS ) + { + /* values look good - replace the values in the attribute */ + if(!valuearray_isempty(vs->va)) + { + /* remove old values */ + slapi_valueset_done(vs); + } + vs->va = vs_new->va; + vs_new->va = NULL; + vs->sorted = vs_new->sorted; + vs_new->sorted = NULL; + vs->num = vs_new->num; + vs->max = vs_new->max; + slapi_valueset_free (vs_new); + } + else + { + /* caller expects us to own valstoreplace - since we cannot + use them, just delete them */ + slapi_valueset_free(vs_new); + valuearray_free(&valstoreplace); + } } return rc; } @@ -1422,46 +1352,33 @@ valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slap if(!valuearray_isempty(valuestoupdate) && !valuearray_isempty(vs->va)) { - /* - * determine whether we should use an AVL tree of values or not - */ struct valuearrayfast vaf_valuesupdated; - int numberofvaluestoupdate= valuearray_count(valuestoupdate); valuearrayfast_init(&vaf_valuesupdated,*valuesupdated); - if (numberofvaluestoupdate > 1) /* multiple values to update */ + int i; + int del_index = -1, del_count = 0; + for (i=0;valuestoupdate[i]!=NULL;++i) { - int i; - Avlnode *vtree = NULL; - int rc= valuetree_add_valuearray( a, vs->va, &vtree, NULL ); - PR_ASSERT(rc==LDAP_SUCCESS); - for (i=0;valuestoupdate[i]!=NULL;++i) + int index= valuearray_find(a, vs->va, valuestoupdate[i]); + if(index!=-1) { - int index= 0; - rc = valuetree_find( a, valuestoupdate[i], vtree, &index ); - if(rc==LDAP_SUCCESS) - { - value_update_csn(vs->va[index],t,csn); - valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); - valuestoupdate[i] = NULL; - } + value_update_csn(vs->va[index],t,csn); + valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); + valuestoupdate[i]= NULL; + del_count++; + if (del_index < 0) del_index = i; } - valuetree_free(&vtree); - } - else - { - int i; - for (i=0;valuestoupdate[i]!=NULL;++i) - { - int index= valuearray_find(a, vs->va, valuestoupdate[i]); - if(index!=-1) - { - value_update_csn(vs->va[index],t,csn); - valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]); - valuestoupdate[i]= NULL; + else + { /* keep the value in valuestoupdate, to keep array compressed, move to first free slot*/ + if (del_index >= 0) { + valuestoupdate[del_index] = valuestoupdate[i]; + del_index++; } } } - valuearray_compress(valuestoupdate,numberofvaluestoupdate); + /* complete compression */ + for (i=0; i