ldap/servers/slapd/modify.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
New commits:
commit 8358b4353257a2755caaf5bbccda7dd23358b164
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri Sep 6 11:55:21 2013 -0400
Ticket 411 - [RFE] mods optimizer
Description: If there is a series of identical operations on the same attribute it
takes
much longer doing each mod seperately, as opposed to combining the
values into
one mod operation. Optimizing this can only safely/efficiently be done
to sequential
ops of the same attribute and mod type. Once the chain is broken, the
optimization
stops for that particular mod, and we start over on the next mod
operation.
https://fedorahosted.org/389/ticket/411
Reviewed by: richm(Thanks!)
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 957f36e..2e9da0e 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -81,6 +81,7 @@ static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods
*smod_un
static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw,
Slapi_Mods *smods);
static int hash_rootpw (LDAPMod **mods);
static int valuearray_init_bervalarray_unhashed_only(struct berval **bvals, Slapi_Value
***cvals);
+static void optimize_mods(Slapi_Mods *smods);
#ifdef LDAP_DEBUG
static const char*
@@ -1041,6 +1042,11 @@ static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char
*old_pw)
}
/*
+ * Optimize the mods - this combines sequential identical attribute modifications.
+ */
+ optimize_mods(&smods);
+
+ /*
* call the pre-mod plugins. if they succeed, call
* the backend mod function. then call the post-mod
* plugins.
@@ -1456,3 +1462,73 @@ hash_rootpw (LDAPMod **mods)
return 0;
}
+/*
+ * optimize_mods()
+ *
+ * If the client send a string identical modifications we might
+ * be able to optimize it for add and delete operations:
+ *
+ * mods[0].mod_op: LDAP_MOD_ADD
+ * mods[0].mod_type: uniqueMember
+ * mods[0].mod_values: <value_0>
+ * mods[1].mod_op: LDAP_MOD_ADD
+ * mods[1].mod_type: uniqueMember
+ * mods[1].mod_values: <value_1>
+ * ...
+ * mods[N].mod_op: LDAP_MOD_ADD
+ * mods[N].mod_type: uniqueMember
+ * mods[N]mod_values: <value_N>
+ *
+ * Optimized to:
+ *
+ * mods[0].mod_op: LDAP_MOD_ADD
+ * mods[0].mod_type: uniqueMember
+ * mods[0].mod_values: <value_0>
+ * <value_1>
+ * ...
+ * <value_N>
+ *
+ * We only optimize operations (ADDs and DELETEs) that are sequential. We
+ * can not look at the all mods(non-sequentially) because we need to keep
+ * the order preserved, and keep processing to a minimum.
+ */
+static void
+optimize_mods(Slapi_Mods *smods){
+ LDAPMod *mod, *prev_mod;
+ int i, mod_count = 0, max_vals = 0;
+
+ prev_mod = slapi_mods_get_first_mod(smods);
+ while((mod = slapi_mods_get_next_mod(smods))){
+ if((SLAPI_IS_MOD_ADD(prev_mod->mod_op) ||
SLAPI_IS_MOD_DELETE(prev_mod->mod_op)) &&
+ (prev_mod->mod_op == mod->mod_op) &&
+ (!strcasecmp(prev_mod->mod_type, mod->mod_type)))
+ {
+ /* Get the current number of mod values from the previous mod. Do it once
per attr */
+ if(mod_count == 0){
+ for(;prev_mod->mod_bvalues != NULL &&
prev_mod->mod_bvalues[mod_count] != NULL; mod_count++);
+ if(mod_count == 0){
+ /* The previous mod did not contain any values, so lets move to the
next mod */
+ prev_mod = mod;
+ continue;
+ }
+ }
+ /* Add the values from the current mod to the prev mod */
+ for ( i = 0; mod->mod_bvalues != NULL && mod->mod_bvalues[i] !=
NULL; i++ ) {
+
bervalarray_add_berval_fast(&(prev_mod->mod_bvalues),mod->mod_bvalues[i],mod_count,
&max_vals);
+ mod_count++;
+ }
+ if(i > 0){
+ /* Ok, we did optimize the "mod" values, so set the current mod
to be ignored */
+ mod->mod_op = LDAP_MOD_IGNORE;
+ } else {
+ /* No mod values, probably a full delete of the attribute... reset
counters and move on */
+ mod_count = max_vals = 0;
+ prev_mod = mod;
+ }
+ } else {
+ /* no match, reset counters and move on */
+ mod_count = max_vals = 0;
+ prev_mod = mod;
+ }
+ }
+}