The branch, v4-0-test has been updated
       via  8c88e4eb1c0a606e7899091525260e8d6558ffd0 (commit)
      from  c4aba5ad01f5095ad7a9d0d0f1e3c6afedbbd9b7 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test


- Log -----------------------------------------------------------------
commit 8c88e4eb1c0a606e7899091525260e8d6558ffd0
Author: Andrew Bartlett <[EMAIL PROTECTED]>
Date:   Wed Jan 16 15:14:05 2008 +1100

    Rework linked_attributes module for the REPLACE case.
    
    This moves to a smarter 'find the delta' based operation of the linked
    attributes module, when the caller asks for a 'replace' of the link
    source.  Previously we would spray operations all over the database,
    even if the net result was just to modify one record.
    
    This also means we need the transaction safety less, which may be
    useful for some LDAP backends that don't provide this functionality on
    the LDAP server.
    
    Andrew Bartlett

-----------------------------------------------------------------------

Summary of changes:
 source/dsdb/samdb/ldb_modules/linked_attributes.c |   92 +++++++++++++++++++--
 1 files changed, 86 insertions(+), 6 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/dsdb/samdb/ldb_modules/linked_attributes.c 
b/source/dsdb/samdb/ldb_modules/linked_attributes.c
index 803d24e..b3fdffe 100644
--- a/source/dsdb/samdb/ldb_modules/linked_attributes.c
+++ b/source/dsdb/samdb/ldb_modules/linked_attributes.c
@@ -279,6 +279,27 @@ static int linked_attributes_add(struct ldb_module 
*module, struct ldb_request *
        return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, 
req->op.add.message->dn);
 }
 
+struct merge {
+       struct ldb_dn *dn;
+       bool add;
+       bool ignore;
+};
+
+static int merge_cmp(struct merge *merge1, struct merge *merge2) {
+       int ret;
+       ret = ldb_dn_compare(merge1->dn, merge2->dn);
+       if (ret == 0) {
+               if (merge1->add == merge2->add) {
+                       return 0;
+               }
+               if (merge1->add == true) {
+                       return 1;
+               }
+               return -1;
+       }
+       return ret;
+}
+
 static int linked_attributes_mod_replace_search_callback(struct ldb_context 
*ldb, void *context, struct ldb_reply *ares) 
 {
        struct replace_context *ac2 = talloc_get_type(context, struct 
replace_context);
@@ -296,16 +317,63 @@ static int 
linked_attributes_mod_replace_search_callback(struct ldb_context *ldb
                
                /* See if this element already exists */
                if (search_el) {
-                       int ret;
+
+                       struct merge *merged_list = NULL;
+
+                       int ret, size = 0, i;
                        struct ldb_message *msg = ldb_msg_new(ac);
                        if (!msg) {
                                ldb_oom(ac->module->ldb);
                                return LDB_ERR_OPERATIONS_ERROR;
                        }
 
-                       /* Lazy option:  Delete and add the elements on all 
members */
-                       msg->num_elements = 1;
-                       msg->elements = search_el;
+                       /* Add all the existing elements, marking as 'proposed 
for delete' by setting .add = false */
+                       for (i=0; i < search_el->num_values; i++) {
+                               merged_list = talloc_realloc(ares, merged_list, 
struct merge, size + 1);
+                               merged_list[size].dn = ldb_dn_new(merged_list, 
ldb, (char *)search_el->values[i].data);
+                               merged_list[size].add = false;
+                               merged_list[size].ignore = false;
+                               size++;
+                       }
+
+                       /* Add all the new replacement elements, marking as 
'proposed for add' by setting .add = true */
+                       for (i=0; i < ac2->el->num_values; i++) {
+                               merged_list = talloc_realloc(ares, merged_list, 
struct merge, size + 1);
+                               merged_list[size].dn = ldb_dn_new(merged_list, 
ldb, (char *)ac2->el->values[i].data);
+                               merged_list[size].add = true;
+                               merged_list[size].ignore = false;
+                               size++;
+                       }
+
+                       /* Sort the list, so we can pick out an add and delete 
for the same DN, and eliminate them */
+                       qsort(merged_list, size,
+                             sizeof(*merged_list),
+                             (comparison_fn_t)merge_cmp);
+
+                       /* Now things are sorted, it is trivial to mark pairs 
of DNs as 'ignore' */
+                       for (i=0; i + 1 < size; i++) {
+                               if (ldb_dn_compare(merged_list[i].dn, 
+                                                  merged_list[i+1].dn) == 0 
+                                   /* Fortunetly the sort also sorts 'add == 
false' first */
+                                   && merged_list[i].add == false
+                                   && merged_list[i+1].add == true) {
+
+                                       /* Mark as ignore, so we include 
neither in the actual operations */
+                                       merged_list[i].ignore = true;
+                                       merged_list[i+1].ignore = true;
+                               }
+                       }
+
+                       /* Arrange to delete anything the search found that we 
don't re-add */
+                       for (i=0; i < size; i++) {
+                               if (merged_list[i].ignore == false
+                                   && merged_list[i].add == false) {
+                                       ldb_msg_add_steal_string(msg, 
search_el->name, 
+                                                                
ldb_dn_get_linearized(merged_list[i].dn));
+                               }
+                       }
+
+                       /* The DN to set on the linked attributes is the 
original DN of the modify message */
                        msg->dn = ac->orig_req->op.mod.message->dn;
                        
                        ret = setup_modifies(ac->module->ldb, ac2, ac, msg, 
ares->message->dn, NULL);
@@ -313,13 +381,21 @@ static int 
linked_attributes_mod_replace_search_callback(struct ldb_context *ldb
                                return ret;
                        }
 
-                       msg->elements = ac2->el;
+                       /* Now add links for all the actually new elements */
+                       for (i=0; i < size; i++) {
+                               if (merged_list[i].ignore == false && 
merged_list[i].add == true) {
+                                       ldb_msg_add_steal_string(msg, 
search_el->name, 
+                                                                
ldb_dn_get_linearized(merged_list[i].dn));
+                               }
+                       }
 
                        ret = setup_modifies(ac->module->ldb, ac2, ac, msg, 
NULL, ares->message->dn);
                        if (ret != LDB_SUCCESS) {
                                return ret;
                        }
                        
+                       talloc_free(merged_list);
+
                } else {
                        /* Looks like it doesn't exist, process like an 'add' */
                        struct ldb_message *msg = ldb_msg_new(ac);
@@ -411,6 +487,7 @@ static int linked_attributes_modify(struct ldb_module 
*module, struct ldb_reques
                        return LDB_ERR_OBJECT_CLASS_VIOLATION;                  
                }
 
+               /* Replace with new set of values */
                if (((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_REPLACE)
                    && el->num_values > 0) {
                        struct replace_context *ac2 = talloc(ac, struct 
replace_context);
@@ -461,6 +538,8 @@ static int linked_attributes_modify(struct ldb_module 
*module, struct ldb_reques
                        }
                        
                        continue;
+
+                       /* Delete all values case */
                } else if (((el->flags & LDB_FLAG_MOD_MASK) & 
(LDB_FLAG_MOD_DELETE|LDB_FLAG_MOD_REPLACE)) 
                           && el->num_values == 0) {
                        const char **attrs = talloc_array(ac, const char *, 2);
@@ -508,7 +587,8 @@ static int linked_attributes_modify(struct ldb_module 
*module, struct ldb_reques
                        
                        continue;
                }
-               /* Prepare the modify (mod element) on the targets */
+
+               /* Prepare the modify (mod element) on the targets, for a 
normal modify request */
 
                /* For each value being moded, we need to setup the modify */
                for (j=0; j < el->num_values; j++) {


-- 
Samba Shared Repository

Reply via email to