From 482e414baf92587cde3ef20faa0f5d68f313ddc6 Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Tue, 9 Apr 2013 14:46:29 +0200
Subject: [PATCH] Ticket 346 - version2 Slow ldapmodify operation time 	for
 large quantities of multi-valued attribute values

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 teh 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

Reviewed by: ?
---
 ldap/servers/slapd/attr.c            |  60 +--
 ldap/servers/slapd/attrlist.c        |   2 +-
 ldap/servers/slapd/attrsyntax.c      |   6 +
 ldap/servers/slapd/back-ldbm/index.c |  27 +-
 ldap/servers/slapd/entry.c           | 121 ++---
 ldap/servers/slapd/entrywsi.c        |   9 +-
 ldap/servers/slapd/proto-slap.h      |  12 +-
 ldap/servers/slapd/slap.h            |   8 +
 ldap/servers/slapd/slapi-plugin.h    |  13 +
 ldap/servers/slapd/slapi-private.h   |   5 +-
 ldap/servers/slapd/valueset.c        | 981 ++++++++++++++++-------------------
 11 files changed, 540 insertions(+), 704 deletions(-)

diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c
index 03b366c..a8c3796 100644
--- a/ldap/servers/slapd/attr.c
+++ b/ldap/servers/slapd/attr.c
@@ -365,11 +365,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;
 }
@@ -835,43 +833,11 @@ 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;
-        } 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;
+	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 defined(USE_OLD_UNHASHED)
                 if (is_type_forbidden(a->a_type)) {
                     /* If the attr is in the forbidden list
@@ -884,22 +850,12 @@ attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn)
 #else
                 rc = LDAP_TYPE_OR_VALUE_EXISTS;
 #endif
-                break;
             }
-        }
-    }
-
-    /*
-     * 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";
 
@@ -940,7 +896,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 1f52bb8..8825e2b 100644
--- a/ldap/servers/slapd/attrlist.c
+++ b/ldap/servers/slapd/attrlist.c
@@ -129,7 +129,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 227369c..43b85e4 100644
--- a/ldap/servers/slapd/attrsyntax.c
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -833,6 +833,10 @@ 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);
  	}
@@ -841,6 +845,8 @@ slapi_attr_is_dn_syntax_attr(Slapi_Attr *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/index.c b/ldap/servers/slapd/back-ldbm/index.c
index a10c67a..88af98a 100644
--- a/ldap/servers/slapd/back-ldbm/index.c
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -545,7 +545,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);
             }
         }
  
@@ -566,7 +566,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);
                 }
             }
                                                                                                                             
@@ -584,7 +584,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 );
                     }
                 }
@@ -593,12 +593,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 */
@@ -611,6 +611,9 @@ index_add_mods(
 
             /* We need to first remove the old values from the 
              * index, if any. */
+	/* do we need to reset array references ? */
+            evals = valueset_get_valuearray(all_vals);
+            deleted_valueArray = valueset_get_valuearray(mod_vals);
             if (deleted_valueArray) {
                 rc = index_addordel_values_sv( be, mods[i]->mod_type,
                                                deleted_valueArray, evals, id, 
@@ -637,8 +640,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,7 +681,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);
                         }
                 }
 
@@ -695,14 +698,14 @@ index_add_mods(
                              * also exist in a subtype.
                              */
                             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 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--;
                                 }
@@ -714,6 +717,8 @@ index_add_mods(
                 }
 
                 /* Update the index, if necessary */
+		/* do we need to reset the array references ? */
+                deleted_valueArray = valueset_get_valuearray(mod_vals);
                 if (deleted_valueArray) {
                     rc = index_addordel_values_sv( be, mods[i]->mod_type,
                                                    deleted_valueArray, evals, id, 
@@ -751,7 +756,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/entry.c b/ldap/servers/slapd/entry.c
index ebd49de..06f078e 100644
--- a/ldap/servers/slapd/entry.c
+++ b/ldap/servers/slapd/entry.c
@@ -237,8 +237,6 @@ str2entry_fast( const char *rawdn, const Slapi_RDN *srdn, char *s, int flags, in
 		int freeval = 0;
 		int value_state= VALUE_NOTFOUND;
 		int attr_state= ATTRIBUTE_NOTFOUND;
-		int maxvals;
-		int del_maxvals;
 
 		if ( *s == '\n' || *s == '\0' ) {
 			break;
@@ -280,9 +278,7 @@ str2entry_fast( const char *rawdn, const Slapi_RDN *srdn, char *s, int flags, in
 			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;
 		}
 
@@ -503,25 +499,21 @@ str2entry_fast( const char *rawdn, const Slapi_RDN *srdn, char *s, int flags, in
 			if(value_state==VALUE_DELETED)
 			{
 				/* consumes the value */
-				valuearray_add_value_fast(
-					&(*a)->a_deleted_values.va, /* JCM .va is private */
+				slapi_valueset_add_attr_value_ext(
+					*a,
+					&(*a)->a_deleted_values,
 					svalue,
-					del_nvals,
-					&del_maxvals,
-					0/*!Exact*/,
-					1/*Passin*/ );
+					SLAPI_VALUE_FLAG_PASSIN );
 				del_nvals++;
 			}
 			else
 			{
 				/* consumes the value */
-				valuearray_add_value_fast(
-					&(*a)->a_present_values.va, /* JCM .va is private */
+				slapi_valueset_add_attr_value_ext(
+					*a,
+					&(*a)->a_present_values,
 					svalue, 
-					nvals,
-					&maxvals, 
-					0 /*!Exact*/, 
-					1 /*Passin*/ );
+					SLAPI_VALUE_FLAG_PASSIN);
 				nvals++;
 			}
 			if(attributedeletioncsn!=NULL)
@@ -602,8 +594,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;
@@ -616,8 +608,8 @@ entry_attr_init(str2entry_attr *sa, const char *type, int state)
 {
     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);
+	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;
@@ -1101,66 +1093,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;
@@ -1175,7 +1121,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;
 		}
@@ -1240,27 +1186,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 */
+				slapi_valueset_add_attr_valuearray_ext(
+					*a,
+					&(*a)->a_present_values,
 					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_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 */
+				slapi_valueset_add_attr_valuearray_ext(
+					*a,
+					&(*a)->a_deleted_values,
 					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_VALUE_FLAG_PASSIN, NULL);
 				sa->sa_deleted_values.num= 0; /* The values have been consumed */
 				if(sa->sa_attributedeletioncsn!=NULL)
 				{
@@ -1307,9 +1247,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)
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 578cb4f..b53f8df 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -464,7 +464,7 @@ 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 +502,7 @@ 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);
@@ -584,7 +584,7 @@ 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] */
@@ -603,7 +603,8 @@ 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 0bb923f..d514924 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -165,13 +165,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 */
 
@@ -182,15 +175,16 @@ 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_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/slap.h b/ldap/servers/slapd/slap.h
index f1cd80e..8137e26 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -450,8 +450,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;
 };
 
@@ -522,6 +528,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 f2dc6af..f0e0aa8 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -4647,6 +4647,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.
@@ -4741,6 +4742,7 @@ void slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval);
  * \see slapi_valueset_next_value()
  */
 void slapi_valueset_add_value_ext(Slapi_ValueSet *vs, 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.
@@ -4796,6 +4798,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
@@ -4826,6 +4838,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 937c2bb..ff5bc2c 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -838,9 +838,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 6bc3ffa..1d495d1 100644
--- a/ldap/servers/slapd/valueset.c
+++ b/ldap/servers/slapd/valueset.c
@@ -527,51 +527,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<j<=k<=n && va[j..k] has been shifted left by (j-i) places &&
- * 	va[k..n] remains to be shifted left by (j-i) places
- * 
- */
-void
-valuearray_compress(Slapi_Value **va,int numvalues)
-{
-	int i = 0;
-	int n= numvalues;
-	while(i<n)
-	{
-		if ( va[i] != NULL ) {
-			i++;
-		} else {
-			int k,j;
-			j = i + 1;
-			/* Find the length of the next run of NULL's */
-			while( j<n && va[j] == NULL) { j++; }
-			/* va[i..j] is all NULL && j<= n */	
-			for ( k = j; k<n; k++ )
-			{
-				va[k - (j-i)] = va[k];
-				va[k] = NULL;
-			}
-			/* va[i..n] has been shifted down by j-i places */
-			n = n - (j-i);
-			/*
-			 * If va[i] in now non null, then bump i,
-			 * if not then we are done anyway (j==n) so can bump it.
-			*/
-			i++;
-		}
-	}
-}
-
 /* <=========================== Value Array Fast ==========================> */
 
 void
@@ -612,237 +567,12 @@ 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()
@@ -861,6 +591,9 @@ slapi_valueset_init(Slapi_ValueSet *vs)
 	if(vs!=NULL)
 	{
 		vs->va= NULL;
+		vs->sorted = NULL;
+		vs->num = 0;
+		vs->max = 0;
 	}
 }
 
@@ -874,6 +607,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;
 	}
 }
 
@@ -898,8 +638,22 @@ slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod)
 void
 valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals)
 {
+	int i, j=0;
 	slapi_valueset_init(vs);
-	valueset_add_valuearray(vs,addvals);
+	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
@@ -907,6 +661,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
@@ -916,6 +672,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 )
 {
@@ -931,15 +696,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)
+{
+	if (NULL != vs)
+	{
+		return (vs->num == 0);
+	}
+	return 1;
 }
 
 int
@@ -953,13 +724,17 @@ Slapi_Value *
 slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v)
 {
 	Slapi_Value *r= NULL;
-	if(!valuearray_isempty(vs->va))
+	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;
 }
@@ -967,16 +742,45 @@ 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_sorted(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v)
+{
+	Slapi_Value *r= NULL;
+	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;
+	}
 }
 
 /* 
@@ -1014,6 +818,15 @@ 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))
@@ -1037,7 +850,7 @@ 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
@@ -1046,9 +859,263 @@ slapi_valueset_add_value_ext(Slapi_ValueSet *vs, Slapi_Value *addval, unsigned l
 	Slapi_Value *oneval[2];
 	oneval[0]= (Slapi_Value*)addval;
 	oneval[1]= NULL;
-	valuearray_add_valuearray(&vs->va, oneval, flags);
+	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;
+ 
+	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)
+	{
+		LDAPDebug( LDAP_DEBUG_ARGS, "valueset_value_syntax_cmp: "
+		    "slapi_attr_values2keys_sv failed for type %s\n",
+		    a->a_type, 0, 0 );
+		/* not sure how to deal with that, the caller will interprete any return code as
+		 * comparison result. Do the best we can 
+		 */
+		rc = strcasecmp(v1->bv.bv_val, v2->bv.bv_val);
+	} 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(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(v1->bv.bv_val, 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
+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;
+	rc = slapi_valueset_add_attr_valuearray_ext(a, vs, oneval, 1, flags, NULL );
+	return (rc);
+}
+
+
 /*
  * The string is passed in by value.
  */
@@ -1068,8 +1135,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
@@ -1118,121 +1207,23 @@ 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 )
-		{
-			/*
-			 * 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
-			{
-				int i;
-				/*
-				 * find and mark all the values that are to be deleted
-				 */
-				for ( i = 0; rc == LDAP_SUCCESS && valuestodelete[i] != NULL; ++i )
-				{
-					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
-					{
-						/* Couldn't find the value to be deleted */
-						if(rc==LDAP_NO_SUCH_ATTRIBUTE && (flags & SLAPI_VALUE_FLAG_IGNOREERROR ))
-						{
-							rc= LDAP_SUCCESS;
-						}
-					}
-				}
-				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]);
+				Slapi_Value *found = valueset_remove_value(a, vs, valuestodelete[i]);
 				if(found!=NULL)
 				{
 					if ( va_out )
@@ -1272,7 +1263,6 @@ valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value
 					}
 				}
 			}
-		}
 		if ( va_out )
 		{
 			*va_out= vaf_out.va;
@@ -1285,88 +1275,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;
 }
@@ -1378,43 +1293,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;
 }
@@ -1431,46 +1356,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<del_count;i++)
+			valuestoupdate[del_index+i]= NULL;
+			
 		*valuesupdated= vaf_valuesupdated.va;
 	}
 }
@@ -1487,4 +1399,3 @@ valuearray_dn_normalize_value(Slapi_Value **vals)
 
 	return rc;
 }
-
-- 
1.7.11.7

