From f8ee773af2fe0146578acd49587afa192a23ebcf Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Mon, 13 Jun 2011 17:35:45 -0400
Subject: [PATCH 2/8] mbof_dn_array structure optimized

---
 src/ldb_modules/memberof.c |  290 ++++++++++++++++++++++++++++----------------
 1 files changed, 185 insertions(+), 105 deletions(-)

diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
index 4fc46fa84529ac1850cdb588ddf69be0f60e8238..85ccd144898e975e09eac6630a0c647c0423a0df 100644
--- a/src/ldb_modules/memberof.c
+++ b/src/ldb_modules/memberof.c
@@ -42,16 +42,19 @@
 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
 #endif
 
-struct mbof_dn_array {
-    struct ldb_dn **dns;
-    int num;
-};
-
 struct mbof_dn {
     struct mbof_dn *next;
     struct ldb_dn *dn;
 };
 
+struct mbof_dn_array {
+    struct mbof_dn *dns;
+    struct mbof_dn *first;
+    struct mbof_dn *last;
+    int allocated;
+    int num;
+};
+
 struct mbof_ctx {
     struct ldb_module *module;
     struct ldb_request *req;
@@ -94,8 +97,7 @@ struct mbof_add_ctx {
 
 struct mbof_del_ancestors_ctx {
     struct mbof_dn_array *new_list;
-    int num_direct;
-    int cur;
+    struct mbof_dn *cur_dn;
 
     struct ldb_message *entry;
 };
@@ -333,6 +335,86 @@ static int mbof_append_addop(struct mbof_add_ctx *add_ctx,
     return LDB_SUCCESS;
 }
 
+#define MBOF_DN_ARRAY_CHUNK 16
+static void mbof_recalculate_dns(struct mbof_dn_array *array, int offset)
+{
+    struct mbof_dn *cur_dn;
+    if (offset == 0) return;
+
+    array->first = (struct mbof_dn *)((char *)array->first + offset);
+    for (cur_dn = array->first; cur_dn; cur_dn = cur_dn->next) {
+        if (cur_dn->next) {
+            cur_dn->next = (struct mbof_dn *)((char *)cur_dn->next + offset);
+        }
+    }
+    array->last = (struct mbof_dn *)((char *)array->last + offset);
+}
+
+static int mbof_grow_dns(struct mbof_dn_array *array)
+{
+    char *orig_pointer = (char *)array->dns;
+    int offset;
+
+    array->dns = talloc_realloc(array, array->dns,
+                                struct mbof_dn,
+                                array->allocated+MBOF_DN_ARRAY_CHUNK);
+    if (!array->dns) {
+        return LDB_ERR_OPERATIONS_ERROR;
+    }
+    array->allocated += MBOF_DN_ARRAY_CHUNK;
+
+    if (orig_pointer) {
+        offset = (char *)array->dns-orig_pointer;
+        mbof_recalculate_dns(array, offset);
+    } else {
+        array->first = array->dns;
+    }
+
+    return LDB_SUCCESS;
+}
+
+static int mbof_next_free_dn(struct mbof_dn_array *array)
+{
+    if (array->dns == NULL)
+        return 0;
+    else
+        return (array->last-array->dns)+1;
+}
+
+static void mbof_delete_dn(struct mbof_dn_array *array,
+                           struct mbof_dn *prev,
+                           struct mbof_dn *del)
+{
+    if (del == array->first || prev == NULL)
+        array->first = del->next;
+    else
+        prev->next = del->next;
+    array->num--;
+}
+
+static int mbof_add_dn(struct mbof_dn_array *array, int pos, struct ldb_dn *dn)
+{
+    int ret;
+    if (pos == array->allocated) {
+        ret = mbof_grow_dns(array);
+        if (ret != LDB_SUCCESS) {
+            return ret;
+        }
+    }
+
+    if (array->last) {
+        array->last->next = &array->dns[pos];
+        array->last = array->last->next;
+    } else {
+        array->last = array->dns;
+    }
+    array->last->dn = dn;
+    array->last->next = NULL;
+    array->num++;
+
+    return LDB_SUCCESS;
+}
+
 static int memberof_recompute_task(struct ldb_module *module,
                                    struct ldb_request *req);
 
@@ -416,12 +498,10 @@ static int memberof_add(struct ldb_module *module, struct ldb_request *req)
     if (!parents) {
         return LDB_ERR_OPERATIONS_ERROR;
     }
-    parents->dns = talloc_array(parents, struct ldb_dn *, 1);
-    if (!parents->dns) {
-        return LDB_ERR_OPERATIONS_ERROR;
+    ret =  mbof_add_dn(parents, 0, add_ctx->msg_dn);
+    if (ret != LDB_SUCCESS) {
+        return ret;
     }
-    parents->dns[0] = add_ctx->msg_dn;
-    parents->num = 1;
 
     /* process new members */
     /* check we are not adding ourselves as member as well */
@@ -659,7 +739,6 @@ static int mbof_next_add_callback(struct ldb_request *req,
  */
 static int mbof_add_operation(struct mbof_add_operation *addop)
 {
-
     TALLOC_CTX *tmp_ctx;
     struct mbof_ctx *ctx;
     struct mbof_add_ctx *add_ctx;
@@ -670,7 +749,9 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
     struct ldb_dn *elval_dn;
     struct ldb_dn *valdn;
     struct mbof_dn_array *parents;
-    int i, j, ret;
+    struct mbof_dn *prev_dn;
+    struct mbof_dn *cur_dn;
+    int i, ret;
     const char *val;
     const char *name;
 
@@ -682,21 +763,16 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
     if (!parents) {
         return LDB_ERR_OPERATIONS_ERROR;
     }
-    /* can't be more than the immediate parent */
-    parents->dns = talloc_array(parents, struct ldb_dn *,
-                                addop->parents->num);
-    if (!parents->dns) {
-        return LDB_ERR_OPERATIONS_ERROR;
-    }
-
     /* create new parent set for this entry */
-    for (i = 0; i < addop->parents->num; i++) {
+    for (cur_dn = addop->parents->first; cur_dn; cur_dn = cur_dn->next) {
         /* never add yourself as memberof */
-        if (ldb_dn_compare(addop->parents->dns[i], addop->entry_dn) == 0) {
+        if (ldb_dn_compare(cur_dn->dn, addop->entry_dn) == 0) {
             continue;
         }
-        parents->dns[parents->num] = addop->parents->dns[i];
-        parents->num++;
+        ret = mbof_add_dn(parents, parents->num, cur_dn->dn);
+        if (ret != LDB_SUCCESS) {
+            return ret;
+        }
     }
 
     /* remove entries that are already there */
@@ -714,18 +790,14 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
                 talloc_free(tmp_ctx);
                 return LDB_ERR_OPERATIONS_ERROR;
             }
-            for (j = 0; j < parents->num; j++) {
-                if (ldb_dn_compare(parents->dns[j], elval_dn) == 0) {
-                    /* duplicate found */
+            /* Filter duplicates */
+            prev_dn = NULL;
+            for (cur_dn = parents->first; cur_dn; cur_dn = cur_dn->next) {
+                if (ldb_dn_compare(cur_dn->dn, elval_dn) == 0) {
+                    mbof_delete_dn(parents, prev_dn, cur_dn);
                     break;
                 }
-            }
-            if (j < parents->num) {
-                /* remove duplicate */
-                for (;j+1 < parents->num; j++) {
-                    parents->dns[j] = parents->dns[j+1];
-                }
-                parents->num--;
+                prev_dn = cur_dn;
             }
         }
 
@@ -785,11 +857,11 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
             return LDB_ERR_OPERATIONS_ERROR;
         }
 
-        for (i = 0; i < parents->num; i++) {
+        for (cur_dn = parents->first; cur_dn; cur_dn = cur_dn->next) {
             ret = mbof_append_muop(add_ctx, &add_ctx->muops,
                                    &add_ctx->num_muops,
                                    LDB_FLAG_MOD_ADD,
-                                   parents->dns[i], name);
+                                   cur_dn->dn, name);
             if (ret != LDB_SUCCESS) {
                 return ret;
             }
@@ -824,17 +896,22 @@ static int mbof_add_operation(struct mbof_add_operation *addop)
     if (!el->values) {
         return LDB_ERR_OPERATIONS_ERROR;
     }
-    for (i = 0, j = 0; i < parents->num; i++) {
-        if (ldb_dn_compare(parents->dns[i], msg->dn) == 0) continue;
-        val = ldb_dn_get_linearized(parents->dns[i]);
-        el->values[j].length = strlen(val);
-        el->values[j].data = (uint8_t *)talloc_strdup(el->values, val);
-        if (!el->values[j].data) {
+
+    i = 0;
+    for (cur_dn = parents->first; cur_dn; cur_dn = cur_dn->next) {
+        if (ldb_dn_compare(cur_dn->dn, msg->dn) == 0) {
+            continue;
+        }
+
+        val = ldb_dn_get_linearized(cur_dn->dn);
+        el->values[i].length = strlen(val);
+        el->values[i].data = (uint8_t *)talloc_strdup(el->values, val);
+        if (!el->values[i].data) {
             return LDB_ERR_OPERATIONS_ERROR;
         }
-        j++;
+        i++;
     }
-    el->num_values = j;
+    el->num_values = i;
 
     ret = ldb_build_mod_req(&mod_req, ldb, add_ctx,
                             msg, NULL,
@@ -1734,7 +1811,7 @@ static int mbof_del_execute_cont(struct mbof_del_operation *delop)
 {
     struct mbof_del_ancestors_ctx *anc_ctx;
     struct mbof_dn_array *new_list;
-    int i;
+    int i, ret;
 
     anc_ctx = talloc_zero(delop, struct mbof_del_ancestors_ctx);
     if (!anc_ctx) {
@@ -1751,10 +1828,11 @@ static int mbof_del_execute_cont(struct mbof_del_operation *delop)
      * equal to the number of objects that have this entry as
      * direct member */
     new_list->num = delop->num_parents;
+    new_list->allocated = new_list->num;
 
     /* attach the list to the operation */
     delop->anc_ctx->new_list = new_list;
-    delop->anc_ctx->num_direct = new_list->num;
+    delop->anc_ctx->cur_dn = new_list->dns;
 
     /* do we have any direct parent at all ? */
     if (new_list->num == 0) {
@@ -1766,13 +1844,19 @@ static int mbof_del_execute_cont(struct mbof_del_operation *delop)
 
     /* fill in the list if we have parents */
     new_list->dns = talloc_zero_array(new_list,
-                                      struct ldb_dn *,
-                                      new_list->num);
+                                      struct mbof_dn,
+                                      new_list->allocated);
     if (!new_list->dns) {
         return LDB_ERR_OPERATIONS_ERROR;
     }
+    new_list->first = new_list->dns;
+
+    new_list->num = 0;
     for (i = 0; i < delop->num_parents; i++) {
-        new_list->dns[i] = delop->parents[i]->dn;
+        ret = mbof_add_dn(new_list, i, delop->parents[i]->dn);
+        if (ret != LDB_SUCCESS) {
+            return ret;
+        }
     }
 
     /* before proceeding we also need to fetch the ancestors (anew as some may
@@ -1786,7 +1870,6 @@ static int mbof_del_ancestors(struct mbof_del_operation *delop)
     struct mbof_del_ctx *del_ctx;
     struct mbof_ctx *ctx;
     struct ldb_context *ldb;
-    struct mbof_dn_array *new_list;
     static const char *attrs[] = { DB_MEMBEROF, NULL };
     struct ldb_request *search;
     int ret;
@@ -1795,10 +1878,9 @@ static int mbof_del_ancestors(struct mbof_del_operation *delop)
     ctx = del_ctx->ctx;
     ldb = ldb_module_get_ctx(ctx->module);
     anc_ctx = delop->anc_ctx;
-    new_list = anc_ctx->new_list;
 
     ret = ldb_build_search_req(&search, ldb, anc_ctx,
-                               new_list->dns[anc_ctx->cur],
+                               anc_ctx->cur_dn->dn,
                                LDB_SCOPE_BASE, NULL, attrs, NULL,
                                delop, mbof_del_anc_callback,
                                ctx->req);
@@ -1820,8 +1902,9 @@ static int mbof_del_anc_callback(struct ldb_request *req,
     struct ldb_message *msg;
     const struct ldb_message_element *el;
     struct mbof_dn_array *new_list;
+    struct mbof_dn *tmp_dn;
     struct ldb_dn *valdn;
-    int i, j, ret;
+    int i, ret;
 
     delop = talloc_get_type(req->context, struct mbof_del_operation);
     del_ctx = delop->del_ctx;
@@ -1883,39 +1966,35 @@ static int mbof_del_anc_callback(struct ldb_request *req,
                     return ldb_module_done(ctx->req, NULL, NULL,
                                            LDB_ERR_OPERATIONS_ERROR);
                 }
-                for (j = 0; j < new_list->num; j++) {
-                    if (ldb_dn_compare(valdn, new_list->dns[j]) == 0)
+
+                for (tmp_dn = new_list->first; tmp_dn; tmp_dn = tmp_dn->next) {
+                    if (ldb_dn_compare(valdn, tmp_dn->dn) == 0)
                         break;
                 }
-                if (j < new_list->num) {
+                if (tmp_dn) {
                     talloc_free(valdn);
                     continue;
                 }
+
                 /* do not re-add the original deleted entry by mistake */
                 if (ldb_dn_compare(valdn, del_ctx->first->entry_dn) == 0) {
                     talloc_free(valdn);
                     continue;
                 }
-                new_list->dns = talloc_realloc(new_list,
-                                               new_list->dns,
-                                               struct ldb_dn *,
-                                               new_list->num + 1);
-                if (!new_list->dns) {
-                    return ldb_module_done(ctx->req, NULL, NULL,
-                                           LDB_ERR_OPERATIONS_ERROR);
+                ret = mbof_add_dn(new_list, mbof_next_free_dn(new_list), valdn);
+                if (ret != LDB_SUCCESS) {
+                    return ret;
                 }
-                new_list->dns[new_list->num] = valdn;
-                new_list->num++;
             }
         }
 
         /* done with this one */
         talloc_free(anc_ctx->entry);
         anc_ctx->entry = NULL;
-        anc_ctx->cur++;
+        anc_ctx->cur_dn = anc_ctx->cur_dn->next;
 
         /* check if we need to process any more */
-        if (anc_ctx->cur < anc_ctx->num_direct) {
+        if (anc_ctx->cur_dn) {
             /* ok process the next one */
             ret = mbof_del_ancestors(delop);
         } else {
@@ -1939,6 +2018,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
     struct mbof_ctx *ctx;
     struct ldb_context *ldb;
     struct mbof_dn_array *new_list;
+    struct mbof_dn *tmp_dn;
     struct ldb_request *mod_req;
     struct ldb_message *msg;
     struct ldb_message_element *el;
@@ -2018,10 +2098,11 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
         if (!el->values) {
             return LDB_ERR_OPERATIONS_ERROR;
         }
-        for (i = 0, j = 0; i < new_list->num; i++) {
-            if (ldb_dn_compare(new_list->dns[i], msg->dn) == 0)
+        for (tmp_dn = new_list->first, j = 0; tmp_dn; tmp_dn = tmp_dn->next) {
+            if (ldb_dn_compare(tmp_dn->dn, msg->dn) == 0)
                 continue;
-            val = ldb_dn_get_linearized(new_list->dns[i]);
+
+            val = ldb_dn_get_linearized(tmp_dn->dn);
             if (!val) {
                 return LDB_ERR_OPERATIONS_ERROR;
             }
@@ -2037,7 +2118,7 @@ static int mbof_del_mod_entry(struct mbof_del_operation *delop)
                  * one and for each missing entry add a memberuid removal
                  * operation */
                 for (k = 0; diff[k]; k++) {
-                    if (ldb_dn_compare(new_list->dns[i], diff[k]) == 0) {
+                    if (ldb_dn_compare(tmp_dn->dn, diff[k]) == 0) {
                         break;
                     }
                 }
@@ -2665,7 +2746,9 @@ static int mbof_mod_process(struct mbof_mod_ctx *mod_ctx, bool *done)
     struct mbof_ctx *ctx;
     struct mbof_dn_array *removed;
     struct mbof_dn_array *added;
-    int i, j, ret;
+    struct mbof_dn *rem_dn, *rem_prev;
+    struct mbof_dn *add_dn, *add_prev;
+    int ret;
 
     ctx = mod_ctx->ctx;
     ldb = ldb_module_get_ctx(ctx->module);
@@ -2722,24 +2805,18 @@ static int mbof_mod_process(struct mbof_mod_ctx *mod_ctx, bool *done)
         }
 
         /* remove from arrays values that ended up unchanged */
+        add_prev = NULL;
+        rem_prev = NULL;
         if (removed && removed->num && added && added->num) {
-            for (i = 0; i < added->num; i++) {
-                for (j = 0; j < removed->num; j++) {
-                    if (ldb_dn_compare(added->dns[i], removed->dns[j]) == 0) {
+            for (add_dn = added->first; add_dn; add_dn = add_dn->next) {
+                for (rem_dn = removed->first; rem_dn; rem_dn = rem_dn->next) {
+                    if (ldb_dn_compare(add_dn->dn, rem_dn->dn) == 0) {
+                        mbof_delete_dn(added, add_prev, add_dn);
+                        mbof_delete_dn(removed, rem_prev, rem_dn);
                         break;
                     }
-                }
-                if (j < removed->num) {
-                    /* preexisting one, not removed, nor added */
-                    for (; j+1 < removed->num; j++) {
-                        removed->dns[j] = removed->dns[j+1];
-                    }
-                    removed->num--;
-                    for (j = i; j+1 < added->num; j++) {
-                        added->dns[j] = added->dns[j+1];
-                    }
-                    added->num--;
-                    i--;
+                    add_prev = add_dn;
+                    rem_prev = rem_dn;
                 }
             }
         }
@@ -2775,10 +2852,11 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
 {
     const struct ldb_message_element *el;
     struct mbof_dn_array *parents;
+    struct mbof_dn *cur_dn;
     struct mbof_add_ctx *add_ctx;
     struct ldb_context *ldb;
     struct mbof_ctx *ctx;
-    int i, ret;
+    int ret;
 
     ctx = mod_ctx->ctx;
     ldb = ldb_module_get_ctx(ctx->module);
@@ -2791,13 +2869,10 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
         return ret;
     }
 
-    parents->dns = talloc_realloc(parents, parents->dns,
-                                  struct ldb_dn *, parents->num + 1);
-    if (!parents->dns) {
-        return LDB_ERR_OPERATIONS_ERROR;
+    ret = mbof_add_dn(parents, mbof_next_free_dn(parents), mod_ctx->entry->dn);
+    if (ret != LDB_SUCCESS) {
+        return ret;
     }
-    parents->dns[parents->num] = mod_ctx->entry->dn;
-    parents->num++;
 
     add_ctx = talloc_zero(mod_ctx, struct mbof_add_ctx);
     if (!add_ctx) {
@@ -2806,8 +2881,8 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
     add_ctx->ctx = ctx;
     add_ctx->msg_dn = mod_ctx->msg->dn;
 
-    for (i = 0; i < ael->num; i++) {
-        ret = mbof_append_addop(add_ctx, parents, ael->dns[i]);
+    for (cur_dn = ael->first; cur_dn; cur_dn = cur_dn->next) {
+        ret = mbof_append_addop(add_ctx, parents, cur_dn->dn);
         if (ret != LDB_SUCCESS) {
             return ret;
         }
@@ -2822,7 +2897,8 @@ static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
     struct mbof_del_operation *first;
     struct mbof_del_ctx *del_ctx;
     struct mbof_ctx *ctx;
-    int i, ret;
+    struct mbof_dn *cur_dn;
+    int ret;
 
     ctx = mod_ctx->ctx;
 
@@ -2847,8 +2923,8 @@ static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
     first->entry_dn = mod_ctx->entry->dn;
 
     /* prepare del sets */
-    for (i = 0; i < del->num; i++) {
-        ret = mbof_append_delop(first, del->dns[i]);
+    for (cur_dn = del->first; cur_dn; cur_dn = cur_dn->next) {
+        ret = mbof_append_delop(first, cur_dn->dn);
         if (ret != LDB_SUCCESS) {
             return ret;
         }
@@ -2870,7 +2946,7 @@ static int mbof_fill_dn_array(TALLOC_CTX *memctx,
 {
     struct mbof_dn_array *ar;
     struct ldb_dn *valdn;
-    int i;
+    int i, ret;
 
     ar = talloc_zero(memctx, struct mbof_dn_array);
     if (!ar) {
@@ -2882,20 +2958,24 @@ static int mbof_fill_dn_array(TALLOC_CTX *memctx,
         return LDB_SUCCESS;
     }
 
-    ar->dns = talloc_array(ar, struct ldb_dn *, el->num_values);
+    ar->dns = talloc_zero_array(ar, struct mbof_dn, el->num_values);
     if (!ar->dns) {
         return LDB_ERR_OPERATIONS_ERROR;
     }
-    ar->num = el->num_values;
+    ar->allocated = el->num_values;
+    ar->first = ar->dns;
 
-    for (i = 0; i < ar->num; i++) {
+    for (i = 0; i < ar->allocated; i++) {
         valdn = ldb_dn_from_ldb_val(ar, ldb, &el->values[i]);
         if (!valdn || !ldb_dn_validate(valdn)) {
             ldb_debug(ldb, LDB_DEBUG_TRACE, "Invalid dn value: [%s]",
                                             (const char *)el->values[i].data);
             return LDB_ERR_INVALID_DN_SYNTAX;
         }
-        ar->dns[i] = valdn;
+        ret = mbof_add_dn(ar, i, valdn);
+        if (ret != LDB_SUCCESS) {
+            return ret;
+        }
     }
 
     return LDB_SUCCESS;
-- 
1.7.4.1

