1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

ldb: Avoid cost of talloc_free() for unmatched messages

Instead, we pay the cost of allocating a copy of the whole message once
and we pay the cost of allocating a "struct ldb_val" that will not be used
for each element in that message.

This differes from the approach of ldb_unpack_data_only_attr_list()
in that we need not allocate each value for a message that we do not
return, so is more efficient for large multi-valued attributes and
un-indexed or poorly indexed searches

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2016-08-26 09:58:38 +12:00 committed by Douglas Bagnall
parent 45373b988d
commit 198471f9ed
3 changed files with 125 additions and 53 deletions

View File

@ -931,6 +931,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
{
struct ldb_context *ldb;
struct ldb_message *msg;
struct ldb_message *filtered_msg;
unsigned int i;
ldb = ldb_module_get_ctx(ac->module);
@ -951,7 +952,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ltdb_search_dn1(ac->module, dn, msg, 0);
ret = ltdb_search_dn1(ac->module, dn, msg, LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC);
talloc_free(dn);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
/* the record has disappeared? yes, this can happen */
@ -977,14 +978,15 @@ static int ltdb_index_filter(const struct dn_list *dn_list,
}
/* filter the attributes that the user wants */
ret = ltdb_filter_attrs(msg, ac->attrs);
ret = ltdb_filter_attrs(ac, msg, ac->attrs, &filtered_msg);
talloc_free(msg);
if (ret == -1) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldb_module_send_entry(ac->req, msg, NULL);
ret = ldb_module_send_entry(ac->req, filtered_msg, NULL);
if (ret != LDB_SUCCESS) {
/* Regardless of success or failure, the msg
* is the callbacks responsiblity, and should

View File

@ -385,81 +385,144 @@ int ltdb_add_attr_results(struct ldb_module *module,
/*
filter the specified list of attributes from a message
removing not requested attrs.
removing not requested attrs from the new message constructed.
The reason this makes a new message is that the old one may not be
individually allocated, which is what our callers expect.
*/
int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg, const char * const *attrs,
struct ldb_message **filtered_msg)
{
unsigned int i;
int keep_all = 0;
struct ldb_message_element *el2;
bool keep_all = false;
bool add_dn = false;
uint32_t num_elements;
uint32_t elements_size;
struct ldb_message *msg2;
msg2 = ldb_msg_new(mem_ctx);
if (msg2 == NULL) {
goto failed;
}
msg2->dn = ldb_dn_copy(msg2, msg->dn);
if (msg2->dn == NULL) {
goto failed;
}
if (attrs) {
/* check for special attrs */
for (i = 0; attrs[i]; i++) {
if (strcmp(attrs[i], "*") == 0) {
keep_all = 1;
int cmp = strcmp(attrs[i], "*");
if (cmp == 0) {
keep_all = true;
break;
}
if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
if (msg_add_distinguished_name(msg) != 0) {
return -1;
}
cmp = ldb_attr_cmp(attrs[i], "distinguishedName");
if (cmp == 0) {
add_dn = true;
}
}
} else {
keep_all = 1;
}
if (keep_all) {
if (msg_add_distinguished_name(msg) != 0) {
return -1;
}
return 0;
keep_all = true;
}
el2 = talloc_array(msg, struct ldb_message_element, msg->num_elements);
if (el2 == NULL) {
return -1;
if (keep_all) {
add_dn = true;
elements_size = msg->num_elements + 1;
/* Shortcuts for the simple cases */
} else if (add_dn && i == 1) {
if (msg_add_distinguished_name(msg2) != 0) {
return -1;
}
*filtered_msg = msg2;
return 0;
} else if (i == 0) {
*filtered_msg = msg2;
return 0;
/* Otherwise we are copying at most as many element as we have attributes */
} else {
elements_size = i;
}
msg2->elements = talloc_array(msg2, struct ldb_message_element,
elements_size);
if (msg2->elements == NULL) goto failed;
num_elements = 0;
for (i = 0; i < msg->num_elements; i++) {
struct ldb_message_element *el = &msg->elements[i];
struct ldb_message_element *el2 = &msg2->elements[num_elements];
unsigned int j;
int found = 0;
for (j = 0; attrs[j]; j++) {
if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
found = 1;
break;
if (keep_all == false) {
bool found = false;
for (j = 0; attrs[j]; j++) {
int cmp = ldb_attr_cmp(el->name, attrs[j]);
if (cmp == 0) {
found = true;
break;
}
}
if (found == false) {
continue;
}
}
*el2 = *el;
el2->name = talloc_strdup(msg2->elements, el->name);
if (el2->name == NULL) {
goto failed;
}
el2->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
if (el2->values == NULL) {
goto failed;
}
for (j=0;j<el->num_values;j++) {
el2->values[j] = ldb_val_dup(el2->values, &el->values[j]);
if (el2->values[j].data == NULL && el->values[j].length != 0) {
goto failed;
}
}
num_elements++;
if (found) {
el2[num_elements] = msg->elements[i];
talloc_steal(el2, el2[num_elements].name);
talloc_steal(el2, el2[num_elements].values);
num_elements++;
/* Pidginhole principle: we can't have more elements
* than the number of attributes if they are unique in
* the DB */
if (num_elements > elements_size) {
goto failed;
}
}
talloc_free(msg->elements);
msg2->num_elements = num_elements;
if (num_elements > 0) {
msg->elements = talloc_realloc(msg, el2, struct ldb_message_element,
num_elements);
if (add_dn) {
if (msg_add_distinguished_name(msg2) != 0) {
return -1;
}
}
if (msg2->num_elements > 0) {
msg2->elements = talloc_realloc(msg2, msg2->elements,
struct ldb_message_element,
msg2->num_elements);
if (msg2->elements == NULL) {
return -1;
}
} else {
msg->elements = talloc_array(msg, struct ldb_message_element, 0);
talloc_free(el2);
}
if (msg->elements == NULL) {
return -1;
talloc_free(msg2->elements);
msg2->elements = NULL;
}
msg->num_elements = num_elements;
*filtered_msg = msg2;
return 0;
failed:
return -1;
}
/*
@ -469,13 +532,14 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
{
struct ldb_context *ldb;
struct ltdb_context *ac;
struct ldb_message *msg;
struct ldb_message *msg, *filtered_msg;
const struct ldb_val val = {
.data = data.dptr,
.length = data.dsize,
};
int ret;
bool matched;
unsigned int nb_elements_in_db;
ac = talloc_get_type(state, struct ltdb_context);
ldb = ldb_module_get_ctx(ac->module);
@ -492,7 +556,11 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
}
/* unpack the record */
ret = ldb_unpack_data(ldb, &val, msg);
ret = ldb_unpack_data_only_attr_list_flags(ldb, &val,
msg,
NULL, 0,
LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC,
&nb_elements_in_db);
if (ret == -1) {
talloc_free(msg);
ac->error = LDB_ERR_OPERATIONS_ERROR;
@ -523,15 +591,15 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
}
/* filter the attributes that the user wants */
ret = ltdb_filter_attrs(msg, ac->attrs);
ret = ltdb_filter_attrs(ac, msg, ac->attrs, &filtered_msg);
talloc_free(msg);
if (ret == -1) {
talloc_free(msg);
ac->error = LDB_ERR_OPERATIONS_ERROR;
return -1;
}
ret = ldb_module_send_entry(ac->req, msg, NULL);
ret = ldb_module_send_entry(ac->req, filtered_msg, NULL);
if (ret != LDB_SUCCESS) {
ac->request_terminated = true;
/* the callback failed, abort the operation */

View File

@ -109,7 +109,9 @@ int ltdb_add_attr_results(struct ldb_module *module,
const char * const attrs[],
unsigned int *count,
struct ldb_message ***res);
int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs);
int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg, const char * const *attrs,
struct ldb_message **filtered_msg);
int ltdb_search(struct ltdb_context *ctx);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */