1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-20 22:50:26 +03:00

r17299: Improve the partition module to replicate attribute records into all

partitions.

Test that we do that correctly.

Andrew Bartlett
(This used to be commit 90c07b88010b848423dee9556a24e8d181c365dd)
This commit is contained in:
Andrew Bartlett 2006-07-29 01:13:53 +00:00 committed by Gerald (Jerry) Carter
parent 4317209606
commit 77bb75ead0
2 changed files with 246 additions and 59 deletions

View File

@ -42,15 +42,16 @@ struct partition {
};
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 @@ struct ldb_module *find_backend(struct ldb_module *module, struct ldb_request *r
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 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
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 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
}
/* 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 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
/* 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 @@ static int partition_rename(struct ldb_module *module, struct ldb_request *req)
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 @@ static int partition_init(struct ldb_module *module)
{
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 @@ static int partition_init(struct ldb_module *module)
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 @@ static int partition_wait_none(struct ldb_handle *handle) {
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;
}
}

View File

@ -101,6 +101,16 @@ partition: cn=Sub,cn=Sub,cn=PartTest:" + prefix + "testsubsub.ldb
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 @@ x: 11
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 @@ x: 11
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();