svn commit: samba r17299 - in branches/SAMBA_4_0: source/dsdb/samdb/ldb_modules testprogs/ejs

abartlet at samba.org abartlet at samba.org
Sat Jul 29 01:13:54 GMT 2006


Author: abartlet
Date: 2006-07-29 01:13:53 +0000 (Sat, 29 Jul 2006)
New Revision: 17299

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=17299

Log:
Improve the partition module to replicate attribute records into all
partitions.

Test that we do that correctly.

Andrew Bartlett

Modified:
   branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/partition.c
   branches/SAMBA_4_0/testprogs/ejs/ldb.js


Changeset:
Modified: branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/partition.c
===================================================================
--- branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/partition.c	2006-07-28 23:46:39 UTC (rev 17298)
+++ branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/partition.c	2006-07-29 01:13:53 UTC (rev 17299)
@@ -42,15 +42,16 @@
 };
 struct partition_private_data {
 	struct partition **partitions;
+	struct ldb_dn **replicate;
 };
 
 struct partition_context {
 	struct ldb_module *module;
 	struct ldb_request *orig_req;
 
-	struct ldb_request **search_req;
-	BOOL *finished_search;
-	int num_searches;
+	struct ldb_request **down_req;
+	int num_requests;
+	int finished_requests;
 };
 
 static struct ldb_handle *partition_init_handle(struct ldb_request *req, struct ldb_module *module)
@@ -118,35 +119,163 @@
 	return module;
 };
 
-static int partition_send_search(struct partition_context *ac, struct ldb_module *partition)
+
+/*
+  fire the caller's callback for every entry, but only send 'done' once.
+*/
+static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
 {
+	struct partition_context *ac;
+
+	if (!context || !ares) {
+		ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+		goto error;
+	}
+
+	ac = talloc_get_type(context, struct partition_context);
+
+	if (ares->type == LDB_REPLY_ENTRY) {
+		return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+	} else {
+		ac->finished_requests++;
+		if (ac->finished_requests == ac->num_requests) {
+			return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+		} else {
+			talloc_free(ares);
+			return LDB_SUCCESS;
+		}
+	}
+error:
+	talloc_free(ares);
+	return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+  only fire the 'last' callback, and only for START-TLS for now 
+*/
+static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+{
+	struct partition_context *ac;
+
+	if (!context || !ares) {
+		ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+		goto error;
+	}
+
+	ac = talloc_get_type(context, struct partition_context);
+
+	if (ares->type == LDB_REPLY_EXTENDED && strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID)) {
+		ac->finished_requests++;
+		if (ac->finished_requests == ac->num_requests) {
+			return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+		}
+		talloc_free(ares);
+		return LDB_SUCCESS;
+	}
+	ldb_set_errstring(ldb, talloc_asprintf(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS"));
+error:
+	talloc_free(ares);
+	return LDB_ERR_OPERATIONS_ERROR;
+}
+
+
+static int partition_send_request(struct partition_context *ac, struct ldb_module *partition)
+{
 	int ret;
 	struct ldb_module *next = make_module_for_next_request(ac->module, ac->module->ldb, partition);
 	
-	ac->search_req = talloc_realloc(ac, ac->search_req, 
-					struct ldb_request *, ac->num_searches + 1);
-	if (!ac->search_req) {
+	ac->down_req = talloc_realloc(ac, ac->down_req, 
+					struct ldb_request *, ac->num_requests + 1);
+	if (!ac->down_req) {
 		ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
-	ac->search_req[ac->num_searches] = talloc(ac, struct ldb_request);
-	if (ac->search_req[ac->num_searches] == NULL) {
+	ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);
+	if (ac->down_req[ac->num_requests] == NULL) {
 		ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 	
-	*ac->search_req[ac->num_searches] = *ac->orig_req; /* copy the request */
+	*ac->down_req[ac->num_requests] = *ac->orig_req; /* copy the request */
 	
+	if (ac->down_req[ac->num_requests]->operation == LDB_SEARCH) {
+		ac->down_req[ac->num_requests]->callback = partition_search_callback;
+		ac->down_req[ac->num_requests]->context = ac;
+	} else {
+		ac->down_req[ac->num_requests]->callback = partition_other_callback;
+		ac->down_req[ac->num_requests]->context = ac;
+	}
+
 	/* Spray off search requests to all backends */
-	ret = ldb_next_request(next, ac->search_req[ac->num_searches]); 
+	ret = ldb_next_request(next, ac->down_req[ac->num_requests]); 
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
 	
-	ac->num_searches++;
+	ac->num_requests++;
 	return LDB_SUCCESS;
 }
 
+/* Send a request down to all the partitions */
+static int partition_send_all(struct ldb_module *module, 
+			      struct partition_context *ac, struct ldb_request *req) 
+{
+	int i;
+	struct partition_private_data *data = talloc_get_type(module->private_data, 
+							      struct partition_private_data);
+	int ret = partition_send_request(ac, module->next);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+	for (i=0; data && data->partitions && data->partitions[i]; i++) {
+		ret = partition_send_request(ac, data->partitions[i]->module);
+		if (ret != LDB_SUCCESS) {
+			return ret;
+		}
+	}
+	return LDB_SUCCESS;
+}
+
+/* Figure out which backend a request needs to be aimed at.  Some
+ * requests must be replicated to all backends */
+static int partition_replicate(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn) 
+{
+	int i;
+	struct ldb_module *backend;
+	struct partition_private_data *data = talloc_get_type(module->private_data, 
+							      struct partition_private_data);
+	
+	/* Is this a special DN, we need to replicate to every backend? */
+	for (i=0; data->replicate && data->replicate[i]; i++) {
+		if (ldb_dn_compare(module->ldb, 
+				   data->replicate[i], 
+				   dn) == 0) {
+			struct ldb_handle *h;
+			struct partition_context *ac;
+			
+			h = partition_init_handle(req, module);
+			if (!h) {
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			/* return our own handle to deal with this call */
+			req->handle = h;
+			
+			ac = talloc_get_type(h->private_data, struct partition_context);
+			
+			return partition_send_all(module, ac, req);
+		}
+	}
+
+	/* Otherwise, we need to find the backend to fire it to */
+
+	/* Find backend */
+	backend = find_backend(module, req, req->op.add.message->dn);
+	
+	/* issue request */
+	return ldb_next_request(backend, req);
+	
+}
+
 /* search */
 static int partition_search(struct ldb_module *module, struct ldb_request *req)
 {
@@ -171,15 +300,12 @@
 		
 		ac = talloc_get_type(h->private_data, struct partition_context);
 		
-		ac->orig_req = req;
-		ac->num_searches = 0;
-
 		for (i=0; data && data->partitions && data->partitions[i]; i++) {
 			/* Find all partitions under the search base */
 			if (ldb_dn_compare_base(module->ldb, 
 						req->op.search.base,
 						data->partitions[i]->dn) == 0) {
-				ret = partition_send_search(ac, data->partitions[i]->module);
+				ret = partition_send_request(ac, data->partitions[i]->module);
 				if (ret != LDB_SUCCESS) {
 					return ret;
 				}
@@ -187,23 +313,10 @@
 		}
 
 		/* Perhaps we didn't match any partitions.  Try the main partition, then all partitions */
-		if (ac->num_searches == 0) {
-			ret = partition_send_search(ac, module->next);
-			if (ret != LDB_SUCCESS) {
-				return ret;
-			}
-			for (i=0; data && data->partitions && data->partitions[i]; i++) {
-				ret = partition_send_search(ac, data->partitions[i]->module);
-				if (ret != LDB_SUCCESS) {
-					return ret;
-				}
-			}
+		if (ac->num_requests == 0) {
+			return partition_send_all(module, ac, req);
 		}
 		
-		ac->finished_search = talloc_zero_array(ac, BOOL, ac->num_searches);
-		if (!ac->finished_search) {
-			return LDB_ERR_OPERATIONS_ERROR;
-		}
 		return LDB_SUCCESS;
 	} else {
 		struct ldb_module *backend = find_backend(module, req, req->op.search.base);
@@ -215,34 +328,19 @@
 /* add */
 static int partition_add(struct ldb_module *module, struct ldb_request *req)
 {
-	/* Find backend */
-	struct ldb_module *backend = find_backend(module, req, req->op.add.message->dn);
-	
-	/* issue request */
-
-	return ldb_next_request(backend, req);
+	return partition_replicate(module, req, req->op.add.message->dn);
 }
 
 /* modify */
 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
 {
-	/* Find backend */
-	struct ldb_module *backend = find_backend(module, req, req->op.mod.message->dn);
-	
-	/* issue request */
-
-	return ldb_next_request(backend, req);
+	return partition_replicate(module, req, req->op.mod.message->dn);
 }
 
 /* delete */
 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
 {
-	/* Find backend */
-	struct ldb_module *backend = find_backend(module, req, req->op.del.dn);
-	
-	/* issue request */
-
-	return ldb_next_request(backend, req);
+	return partition_replicate(module, req, req->op.del.dn);
 }
 
 /* rename */
@@ -256,10 +354,7 @@
 		return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
 	}
 
-	/* issue request */
-
-	/* (later) consider if we should be searching multiple partitions */
-	return ldb_next_request(backend, req);
+	return partition_replicate(module, req, req->op.rename.olddn);
 }
 
 /* start a transaction */
@@ -400,10 +495,11 @@
 {
 	int ret, i;
 	TALLOC_CTX *mem_ctx = talloc_new(module);
-	static const char *attrs[] = { "partition", NULL };
+	static const char *attrs[] = { "partition", "replicateEntries", NULL };
 	struct ldb_result *res;
 	struct ldb_message *msg;
 	struct ldb_message_element *partition_attributes;
+	struct ldb_message_element *replicate_attributes;
 
 	struct partition_private_data *data;
 
@@ -511,6 +607,32 @@
 		talloc_free(req);
 	}
 
+	replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
+	if (!replicate_attributes) {
+		ldb_set_errstring(module->ldb, 
+				  talloc_asprintf(module, "partition_init: "
+						  "no entries to replicate specified"));
+		data->replicate = NULL;
+	} else {
+		data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
+		if (!data->replicate) {
+			talloc_free(mem_ctx);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		
+		for (i=0; i < replicate_attributes->num_values; i++) {
+			data->replicate[i] = ldb_dn_explode(data->replicate[i], replicate_attributes->values[i].data);
+			if (!data->replicate[i]) {
+				ldb_set_errstring(module->ldb, 
+						  talloc_asprintf(module, "partition_init: "
+								  "invalid DN in partition replicate record: %s", 
+								  replicate_attributes->values[i].data));
+				return LDB_ERR_CONSTRAINT_VIOLATION;
+			}
+		}
+		data->replicate[i] = NULL;
+	}
+
 	module->private_data = data;
 	talloc_steal(module, data);
 	
@@ -536,19 +658,19 @@
 
 	ac = talloc_get_type(handle->private_data, struct partition_context);
 
-	for (i=0; i < ac->num_searches; i++) {
-		ret = ldb_wait(ac->search_req[i]->handle, LDB_WAIT_NONE);
+	for (i=0; i < ac->num_requests; i++) {
+		ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
 		
 		if (ret != LDB_SUCCESS) {
 			handle->status = ret;
 			goto done;
 		}
-		if (ac->search_req[i]->handle->status != LDB_SUCCESS) {
-			handle->status = ac->search_req[i]->handle->status;
+		if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
+			handle->status = ac->down_req[i]->handle->status;
 			goto done;
 		}
 		
-		if (ac->search_req[i]->handle->state != LDB_ASYNC_DONE) {
+		if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
 			return LDB_SUCCESS;
 		}
 	}

Modified: branches/SAMBA_4_0/testprogs/ejs/ldb.js
===================================================================
--- branches/SAMBA_4_0/testprogs/ejs/ldb.js	2006-07-28 23:46:39 UTC (rev 17298)
+++ branches/SAMBA_4_0/testprogs/ejs/ldb.js	2006-07-29 01:13:53 UTC (rev 17299)
@@ -101,6 +101,16 @@
 function modules_test(ldb) 
 {
         println("Running modules tests");
+
+        ok = ldb.add("
+dn: @ATTRIBUTES
+caseattr: CASE_INSENSITIVE
+");
+	if (!ok) {
+		println("Failed to add: " + ldb.errstring());
+		assert(ok);
+	}
+
 	ok = ldb.add("
 dn: cn=x8,cn=PartTest
 objectClass: foo
@@ -207,6 +217,57 @@
 	assert(res8[0].name == "x11");
 	assert(res8[0].cn == "x11");
 
+	ok = ldb.add("
+dn: caseattr=XY,cn=PartTest
+objectClass: foo
+x: Y
+");
+	if (!ok) {
+		println("Failed to add: " + ldb.errstring());
+		assert(ok);
+	}
+
+	ok = ldb.add("
+dn: caseattr=XZ,cn=PartTest
+objectClass: foo
+x: Z
+caseattr: XZ
+");
+	if (!ok) {
+		println("Failed to add: " + ldb.errstring());
+		assert(ok);
+	}
+
+	ok = ldb.add("
+dn: caseattr2=XZ,cn=PartTest
+objectClass: foo
+x: Z
+caseattr2: XZ
+");
+	if (!ok) {
+		println("Failed to add: " + ldb.errstring());
+		assert(ok);
+	}
+
+	var resX = ldb.search("caseattr=xz", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
+	assert(resX.length == 1); 
+	assert(resX[0].objectGUID != undefined);
+	assert(resX[0].createTimestamp != undefined);
+	assert(resX[0].whenCreated != undefined);
+	assert(resX[0].name == "XZ");
+
+	var rescount = ldb.search("(|(caseattr=*)(cn=*))", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
+	assert(rescount.length == 5); 
+
+	/* Check this attribute is *not* case sensitive */
+	var resXcount = ldb.search("caseattr=x*", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
+	assert(resXcount.length == 2); 
+	
+	/* Check that this attribute *is* case sensitive */
+	var resXcount2 = ldb.search("caseattr2=xz", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
+	assert(resXcount2.length == 0); 
+	
+
 	/* Now abort the transaction to show that even with
 	 * partitions, it is aborted everywhere */
 	ok = ldb.transaction_cancel();
@@ -229,6 +290,10 @@
 	var res11 = ldb.search("x=10", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
 	assert(res11.length == 0);
 
+	var attrs = new Array("*");
+	var res12 = ldb.search("caseattr=*", "cn=parttest", ldb.SCOPE_DEFAULT, attrs);
+	assert(res12.length == 0);
+
 }
 
 sys = sys_init();



More information about the samba-cvs mailing list