From: Andrew Bartlett Date: Fri, 3 Feb 2017 02:34:17 +0000 (+1300) Subject: replmd linked attributes: lazy parsing for trusted DNs X-Git-Tag: talloc-2.1.9~242 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=47efee074a82a5f203652302f1fe7a66cdfa7b34;p=thirdparty%2Fsamba.git replmd linked attributes: lazy parsing for trusted DNs If we know that links from the database are in sorted order (via the replmd_private->sorted_links flag), we can avoid actually parsing them until it is absolutely necessary. In many cases we are adding a single link to a long list. The location of the single link is found via a binary search, so we end up parsing log(N) DNs instead of N. Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett --- diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 1cb36be6736..bdb1a8d9f8d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1820,11 +1820,23 @@ static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx, * * That is, if (as is expected in most cases) you get a non-zero * result, you don't need to check for errors. + * + * We assume the second argument refers to a DN is from the database + * and has a GUID -- but this GUID might not have been parsed out yet. */ NTSTATUS status; if (GUID_all_zero(&p->guid)) { + if (p->dsdb_dn == NULL) { + p->dsdb_dn = dsdb_dn_parse_trusted(ctx->mem_ctx, ctx->ldb, p->v, + ctx->ldap_oid); + if (p->dsdb_dn == NULL) { + ctx->err = LDB_ERR_INVALID_DN_SYNTAX; + return 0; + } + } + status = dsdb_get_extended_dn_guid(p->dsdb_dn->dn, &p->guid, "GUID"); if (!NT_STATUS_IS_OK(status)) { ctx->err = LDB_ERR_OPERATIONS_ERROR; @@ -1885,6 +1897,13 @@ static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn, for (i = 0; i < count; i++) { int cmp; p = &pdn[i]; + if (p->dsdb_dn == NULL) { + p->dsdb_dn = dsdb_dn_parse_trusted(pdn, ldb, + p->v, ldap_oid); + if (p->dsdb_dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn); if (cmp == 0) { dsdb_get_extended_dn_guid(p->dsdb_dn->dn, @@ -1999,6 +2018,49 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_SUCCESS; } +/* + * Get a series of trusted message element values. The result is sorted by + * GUID, even though the GUIDs might not be known. That works because we trust + * the database to give us the elements like that if the + * replmd_private->sorted_links flag is set. + */ +static int get_parsed_dns_trusted(struct ldb_module *module, + struct replmd_private *replmd_private, + TALLOC_CTX *mem_ctx, + struct ldb_message_element *el, + struct parsed_dn **pdn, + const char *ldap_oid, + struct ldb_request *parent) +{ + unsigned int i; + + if (el == NULL) { + *pdn = NULL; + return LDB_SUCCESS; + } + + if (!replmd_private->sorted_links) { + /* We need to sort the list. This is the slow old path we want + to avoid. + */ + return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid, + parent); + } + /* Here we get a list of 'struct parsed_dns' without the parsing */ + *pdn = talloc_zero_array(mem_ctx, struct parsed_dn, + el->num_values); + if (!*pdn) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < el->num_values; i++) { + (*pdn)[i].v = &el->values[i]; + } + + return LDB_SUCCESS; +} + /* build a new extended DN, including all meta data fields @@ -2271,13 +2333,24 @@ static int replmd_modify_la_add(struct ldb_module *module, unix_to_nt_time(&now, t); - ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent); + /* get the DNs to be added, fully parsed. + * + * We need full parsing because they came off the wire and we don't + * trust them, besides which we need their details to know where to put + * them. + */ + ret = get_parsed_dns(module, tmp_ctx, el, &dns, + schema_attr->syntax->ldap_oid, parent); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } - ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent); + /* get the existing DNs, lazily parsed */ + ret = get_parsed_dns_trusted(module, replmd_private, + tmp_ctx, old_el, &old_dns, + schema_attr->syntax->ldap_oid, parent); + if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret;