[PATCH] Final Fix for DNS wildcard performance regression

Andrew Bartlett abartlet at samba.org
Mon Dec 18 23:21:33 UTC 2017


On Mon, 2017-12-18 at 17:32 +1300, Andrew Bartlett wrote:
> On Mon, 2017-12-18 at 17:19 +1300, Andrew Bartlett via samba-technical
> wrote:
> > On Mon, 2017-12-18 at 13:21 +1300, Andrew Bartlett wrote:
> > > The attached patches for master partially address the DNS performance
> > > regression found in Samba 4.7.3.
> > 
> > I've looked into this some more, and the attached patches finish the
> > job and return the performance to the original behaviour. 
> > 
> > These are for master, a backport to 4.7 I'll try once it lands.  In the
> > meantime the patch posted earlier will help a lot.
> > 
> > Please review and push!
> 
> Now with more BUG tags.

Attached is the final version.  Once that is in we can backport the
variant (attached) to 4.7.  

I need this in master first however to get commit hashes. 

Please review and push!

Thanks,

Andrew Bartlett
-- 
Andrew Bartlett
https://samba.org/~abartlet/
Authentication Developer, Samba Team         https://samba.org
Samba Development and Support, Catalyst IT   
https://catalyst.net.nz/services/samba



-------------- next part --------------
From c859dd477fe029d7eb491cd6027680973bf712bc Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 18 Dec 2017 16:22:01 +1300
Subject: [PATCH 1/4] ldb: Intersect the index from SCOPE_ONELEVEL with the
 index for the search expression

This helps ensure we do not have to scan all objects at this level
which could be very many (one per DNS zone entry).

However, due to the O(n*m) behaviour in list_intersect() for older
databases, we only do this in the GUID index mode, leaving the behaviour
unchanged for existing callers that do not specify the GUID index mode.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ldb_tdb/ldb_index.c | 60 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 0afeae57a60..9de3683127a 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -151,6 +151,13 @@ ldb_schema_set_override_GUID_index() must be called.
 struct dn_list {
 	unsigned int count;
 	struct ldb_val *dn;
+	/*
+	 * Do not optimise the intersection of this list,
+	 * we must never return an entry not in this
+	 * list.  This allows the index for
+	 * SCOPE_ONELEVEL to be trusted.
+	 */
+	bool strict;
 };
 
 struct ltdb_idxptr {
@@ -1029,10 +1036,10 @@ static bool list_intersect(struct ldb_context *ldb,
 	   what really matches, as all results are filtered by the
 	   full expression at the end - this shortcut avoids a lot of
 	   work in some cases */
-	if (list->count < 2 && list2->count > 10) {
+	if (list->count < 2 && list2->count > 10 && list2->strict == false) {
 		return true;
 	}
-	if (list2->count < 2 && list->count > 10) {
+	if (list2->count < 2 && list->count > 10 && list->strict == false) {
 		list->count = list2->count;
 		list->dn = list2->dn;
 		/* note that list2 may not be the parent of list2->dn,
@@ -1073,6 +1080,7 @@ static bool list_intersect(struct ldb_context *ldb,
 		}
 	}
 
+	list->strict |= list2->strict;
 	list->dn = talloc_steal(list, list3->dn);
 	list->count = list3->count;
 	talloc_free(list3);
@@ -1411,6 +1419,8 @@ static int ltdb_index_dn_one(struct ldb_module *module,
 			     struct ldb_dn *parent_dn,
 			     struct dn_list *list)
 {
+	/* Ensure we do not shortcut on intersection for this list */
+	list->strict = true;
 	return ltdb_index_dn_attr(module, ltdb,
 				  LTDB_IDXONE, parent_dn, list);
 }
@@ -1630,6 +1640,7 @@ static void ltdb_dn_list_sort(struct ltdb_private *ltdb,
 */
 int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 {
+	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
 	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(ac->module), struct ltdb_private);
 	struct dn_list *dn_list;
 	int ret;
@@ -1677,8 +1688,51 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 			talloc_free(dn_list);
 			return ret;
 		}
-		break;
 
+		/*
+		 * If we have too many matches, running the filter
+		 * tree over the SCOPE_ONELEVEL can be quite expensive
+		 * so we now check the filter tree index as well.
+		 *
+		 * We only do this in the GUID index mode, which is
+		 * O(n*log(m)) otherwise the intersection below will
+		 * be too costly at O(n*m).
+		 *
+		 * We don't set a heuristic for 'too many' but instead
+		 * do it always and rely on the index lookup being
+		 * fast enough in the small case.
+		 */
+		if (ltdb->cache->GUID_index_attribute != NULL) {
+			struct dn_list *idx_one_tree_list
+				= talloc_zero(ac, struct dn_list);
+			if (idx_one_tree_list == NULL) {
+				return ldb_module_oom(ac->module);
+			}
+
+			if (!ltdb->cache->attribute_indexes) {
+				talloc_free(idx_one_tree_list);
+				talloc_free(dn_list);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			/*
+			 * Here we load the index for the tree.
+			 */
+			ret = ltdb_index_dn(ac->module, ltdb, ac->tree,
+					    idx_one_tree_list);
+			if (ret != LDB_SUCCESS) {
+				talloc_free(idx_one_tree_list);
+				talloc_free(dn_list);
+				return ret;
+			}
+
+			if (!list_intersect(ldb, ltdb,
+					    dn_list, idx_one_tree_list)) {
+				talloc_free(idx_one_tree_list);
+				talloc_free(dn_list);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+		}
+		break;
 	case LDB_SCOPE_SUBTREE:
 	case LDB_SCOPE_DEFAULT:
 		if (!ltdb->cache->attribute_indexes) {
-- 
2.11.0


From 5f15965ebdd70ee9642f87e08db03ea10cf395bb Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 18 Dec 2017 16:22:23 +1300
Subject: [PATCH 2/4] dns_server: Use the indexed "name" attribute in wildcard
 lookup

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index 217e65b39f4..a6fe4804130 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -305,6 +305,8 @@ static unsigned int number_of_labels(const struct ldb_val *name) {
  *
  * x.y.z -> (|(name=x.y.z)(name=\2a.y.z)(name=\2a.z)(name=\2a))
  *
+ * The attribute 'name' is used as this is what the LDB index is on
+ *
  * Returns NULL if unable to build the query.
  *
  * The first component of the DN is assumed to be the name being looked up
@@ -318,7 +320,7 @@ static struct ldb_parse_tree *build_wildcard_query(
 {
 	const struct ldb_val *name = NULL;            /* The DNS name being
 							 queried */
-	const char *attr = NULL;                      /* The attribute name */
+	const char *attr = "name";                    /* The attribute name */
 	struct ldb_parse_tree *query = NULL;          /* The constructed query
 							 parse tree*/
 	struct ldb_parse_tree *wildcard_query = NULL; /* The parse tree for the
@@ -326,12 +328,6 @@ static struct ldb_parse_tree *build_wildcard_query(
 							 entries */
 	int labels = 0;         /* The number of labels in the name */
 
-	attr = ldb_dn_get_rdn_name(dn);
-	if (attr == NULL) {
-		DBG_ERR("Unable to get rdn_name\n");
-		return NULL;
-	}
-
 	name = ldb_dn_get_rdn_val(dn);
 	if (name == NULL) {
 		DBG_ERR("Unable to get domain name value\n");
-- 
2.11.0


From 6cb9532104f125ea9e3f553561df49976d843300 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 15 Dec 2017 11:40:28 +1300
Subject: [PATCH 3/4] dns_server: Do not look for a wildcard for @

This query is made for every record returned via BIND9 DLZ.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index a6fe4804130..b2b2d1f4e1a 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -543,6 +543,16 @@ WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
 		return DNS_ERR(NAME_ERROR);
 	}
 
+	/* Don't look for a wildcard for @ */
+	if (name->length == 1 && name->data[0] == '@') {
+		return dns_common_lookup(samdb,
+					 mem_ctx,
+					 dn,
+					 records,
+					 num_records,
+					 NULL);
+	}
+
 	werr =  dns_name_check(
 			mem_ctx,
 			strlen((const char*)name->data),
-- 
2.11.0


From 95e39dde28cd5441c87a29b676fca17f6e3fc8fb Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 15 Dec 2017 12:30:50 +1300
Subject: [PATCH 4/4] dns_server: Do the exact match query first, then do the
 wildcard lookup

The wildcard lookup is SCOPE_ONELEVEL combined with an index on the name
attribute.  This is not as efficient as a base DN lookup, so we try for
that first.

A not-found and wildcard response will still fall back to the ONELEVEL
index.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index b2b2d1f4e1a..cea322947eb 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -561,6 +561,20 @@ WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
 		return werr;
 	}
 
+	/*
+	 * Do a point search first, then fall back to a wildcard
+	 * lookup if it does not exist
+	 */
+	werr = dns_common_lookup(samdb,
+				 mem_ctx,
+				 dn,
+				 records,
+				 num_records,
+				 NULL);
+	if (!W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+		return werr;
+	}
+
 	ret = dns_wildcard_lookup(samdb, mem_ctx, dn, &msg);
 	if (ret == LDB_ERR_OPERATIONS_ERROR) {
 		return DNS_ERR(SERVER_FAILURE);
-- 
2.11.0

-------------- next part --------------
From 28cb9f5c6d9b9441a418a8cc50245bb6fd262490 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 10 Aug 2017 16:23:33 +1200
Subject: [PATCH 1/6] ldb_tdb: Provide struct ltdb_private to index routines

This will make it easier to switch the GUID index mode on and off

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Garming Sam <garming at catalyst.net.nz>
(cherry picked from commit 3d952157d72b3a4635f3942449c1727c438c97c6)
---
 lib/ldb/ldb_tdb/ldb_index.c | 90 ++++++++++++++++++++++++++++++---------------
 lib/ldb/ldb_tdb/ldb_tdb.c   | 38 +++++++++++++------
 lib/ldb/ldb_tdb/ldb_tdb.h   | 16 ++++++--
 3 files changed, 99 insertions(+), 45 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index 3510dd9b1bc..ddcf0124dab 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -79,7 +79,9 @@ static int dn_list_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
   find a entry in a dn_list, using a ldb_val. Uses a case sensitive
   comparison with the dn returns -1 if not found
  */
-static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_val *v)
+static int ltdb_dn_list_find_val(struct ltdb_private *ltdb,
+				 const struct dn_list *list,
+				 const struct ldb_val *v)
 {
 	unsigned int i;
 	for (i=0; i<list->count; i++) {
@@ -94,12 +96,14 @@ static int ltdb_dn_list_find_val(const struct dn_list *list, const struct ldb_va
   find a entry in a dn_list. Uses a case sensitive comparison with the dn
   returns -1 if not found
  */
-static int ltdb_dn_list_find_str(struct dn_list *list, const char *dn)
+static int ltdb_dn_list_find_str(struct ltdb_private *ltdb,
+				 struct dn_list *list,
+				 const char *dn)
 {
 	struct ldb_val v;
 	v.data = discard_const_p(unsigned char, dn);
 	v.length = strlen(dn);
-	return ltdb_dn_list_find_val(list, &v);
+	return ltdb_dn_list_find_val(ltdb, list, &v);
 }
 
 /*
@@ -219,7 +223,9 @@ normal_index:
 /*
   save a dn_list into a full @IDX style record
  */
-static int ltdb_dn_list_store_full(struct ldb_module *module, struct ldb_dn *dn,
+static int ltdb_dn_list_store_full(struct ldb_module *module,
+				   struct ltdb_private *ltdb,
+				   struct ldb_dn *dn,
 				   struct dn_list *list)
 {
 	struct ldb_message *msg;
@@ -274,7 +280,8 @@ static int ltdb_dn_list_store(struct ldb_module *module, struct ldb_dn *dn,
 	struct dn_list *list2;
 
 	if (ltdb->idxptr == NULL) {
-		return ltdb_dn_list_store_full(module, dn, list);
+		return ltdb_dn_list_store_full(module, ltdb,
+					       dn, list);
 	}
 
 	if (ltdb->idxptr->itdb == NULL) {
@@ -345,7 +352,8 @@ static int ltdb_index_traverse_store(struct tdb_context *tdb, TDB_DATA key, TDB_
 		return -1;
 	}
 
-	ltdb->idxptr->error = ltdb_dn_list_store_full(module, dn, list);
+	ltdb->idxptr->error = ltdb_dn_list_store_full(module, ltdb,
+						      dn, list);
 	talloc_free(dn);
 	if (ltdb->idxptr->error != 0) {
 		return -1;
@@ -575,6 +583,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module,
   list = list & list2
 */
 static bool list_intersect(struct ldb_context *ldb,
+			   struct ltdb_private *ltdb,
 			   struct dn_list *list, const struct dn_list *list2)
 {
 	struct dn_list *list3;
@@ -622,7 +631,8 @@ static bool list_intersect(struct ldb_context *ldb,
 	list3->count = 0;
 
 	for (i=0;i<list->count;i++) {
-		if (ltdb_dn_list_find_val(list2, &list->dn[i]) != -1) {
+		if (ltdb_dn_list_find_val(ltdb, list2,
+					  &list->dn[i]) != -1) {
 			list3->dn[list3->count] = list->dn[i];
 			list3->count++;
 		}
@@ -846,7 +856,8 @@ static int ltdb_index_dn_and(struct ldb_module *module,
 			list->dn = list2->dn;
 			list->count = list2->count;
 			found = true;
-		} else if (!list_intersect(ldb, list, list2)) {
+		} else if (!list_intersect(ldb, ltdb,
+					   list, list2)) {
 			talloc_free(list2);
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
@@ -952,7 +963,8 @@ static int ltdb_index_dn(struct ldb_module *module,
   filter a candidate dn_list from an indexed search into a set of results
   extracting just the given attributes
 */
-static int ltdb_index_filter(const struct dn_list *dn_list,
+static int ltdb_index_filter(struct ltdb_private *ltdb,
+			     const struct dn_list *dn_list,
 			     struct ltdb_context *ac,
 			     uint32_t *match_count)
 {
@@ -1123,7 +1135,7 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 		break;
 	}
 
-	ret = ltdb_index_filter(dn_list, ac, match_count);
+	ret = ltdb_index_filter(ltdb, dn_list, ac, match_count);
 	talloc_free(dn_list);
 	return ret;
 }
@@ -1148,7 +1160,9 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
  *
  * @return                  An ldb error code
  */
-static int ltdb_index_add1(struct ldb_module *module, const char *dn,
+static int ltdb_index_add1(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   const char *dn,
 			   struct ldb_message_element *el, int v_idx)
 {
 	struct ldb_context *ldb;
@@ -1227,12 +1241,15 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn,
 /*
   add index entries for one elements in a message
  */
-static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
+static int ltdb_index_add_el(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
+			     const char *dn,
 			     struct ldb_message_element *el)
 {
 	unsigned int i;
 	for (i = 0; i < el->num_values; i++) {
-		int ret = ltdb_index_add1(module, dn, el, i);
+		int ret = ltdb_index_add1(module, ltdb,
+					  dn, el, i);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1244,11 +1261,12 @@ static int ltdb_index_add_el(struct ldb_module *module, const char *dn,
 /*
   add index entries for all elements in a message
  */
-static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
+static int ltdb_index_add_all(struct ldb_module *module,
+			      struct ltdb_private *ltdb,
+			      const char *dn,
 			      struct ldb_message_element *elements,
 			      unsigned int num_el)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	unsigned int i;
 
 	if (dn[0] == '@') {
@@ -1265,7 +1283,7 @@ static int ltdb_index_add_all(struct ldb_module *module, const char *dn,
 		if (!ltdb_is_indexed(module, ltdb, elements[i].name)) {
 			continue;
 		}
-		ret = ltdb_index_add_el(module, dn, &elements[i]);
+		ret = ltdb_index_add_el(module, ltdb, dn, &elements[i]);
 		if (ret != LDB_SUCCESS) {
 			struct ldb_context *ldb = ldb_module_get_ctx(module);
 			ldb_asprintf_errstring(ldb,
@@ -1321,9 +1339,9 @@ static int ltdb_index_onelevel(struct ldb_module *module,
 	el.num_values = 1;
 
 	if (add) {
-		ret = ltdb_index_add1(module, dn, &el, 0);
+		ret = ltdb_index_add1(module, ltdb, dn, &el, 0);
 	} else { /* delete */
-		ret = ltdb_index_del_value(module, msg->dn, &el, 0);
+		ret = ltdb_index_del_value(module, ltdb, msg->dn, &el, 0);
 	}
 
 	talloc_free(pdn);
@@ -1335,23 +1353,27 @@ static int ltdb_index_onelevel(struct ldb_module *module,
   add the index entries for a new element in a record
   The caller guarantees that these element values are not yet indexed
 */
-int ltdb_index_add_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_add_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	if (ldb_dn_is_special(dn)) {
 		return LDB_SUCCESS;
 	}
 	if (!ltdb_is_indexed(module, ltdb, el->name)) {
 		return LDB_SUCCESS;
 	}
-	return ltdb_index_add_el(module, ldb_dn_get_linearized(dn), el);
+	return ltdb_index_add_el(module, ltdb,
+				 ldb_dn_get_linearized(dn), el);
 }
 
 /*
   add the index entries for a new record
 */
-int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
+int ltdb_index_add_new(struct ldb_module *module,
+		       struct ltdb_private *ltdb,
+		       const struct ldb_message *msg)
 {
 	const char *dn;
 	int ret;
@@ -1365,7 +1387,8 @@ int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements);
+	ret = ltdb_index_add_all(module, ltdb, dn, msg->elements,
+				 msg->num_elements);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -1377,7 +1400,9 @@ int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg)
 /*
   delete an index entry for one message element
 */
-int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_value(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 struct ldb_dn *dn,
 			 struct ldb_message_element *el, unsigned int v_idx)
 {
 	struct ldb_context *ldb;
@@ -1422,7 +1447,7 @@ int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
 		return ret;
 	}
 
-	i = ltdb_dn_list_find_str(list, dn_str);
+	i = ltdb_dn_list_find_str(ltdb, list, dn_str);
 	if (i == -1) {
 		/* nothing to delete */
 		talloc_free(dn_key);
@@ -1452,10 +1477,11 @@ int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
   delete the index entries for a element
   return -1 on failure
 */
-int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el)
 {
-	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);
 	const char *dn_str;
 	int ret;
 	unsigned int i;
@@ -1478,7 +1504,7 @@ int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
 		return LDB_SUCCESS;
 	}
 	for (i = 0; i < el->num_values; i++) {
-		ret = ltdb_index_del_value(module, dn, el, i);
+		ret = ltdb_index_del_value(module, ltdb, dn, el, i);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1512,7 +1538,8 @@ int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg)
 	}
 
 	for (i = 0; i < msg->num_elements; i++) {
-		ret = ltdb_index_del_element(module, msg->dn, &msg->elements[i]);
+		ret = ltdb_index_del_element(module, ltdb,
+					     msg->dn, &msg->elements[i]);
 		if (ret != LDB_SUCCESS) {
 			return ret;
 		}
@@ -1677,6 +1704,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 	struct ldb_context *ldb;
 	struct ltdb_reindex_context *ctx = (struct ltdb_reindex_context *)state;
 	struct ldb_module *module = ctx->module;
+	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module),
+						    struct ltdb_private);
 	struct ldb_message *msg;
 	const char *dn = NULL;
 	unsigned int nb_elements_in_db;
@@ -1738,7 +1767,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *
 		return -1;
 	}
 
-	ret = ltdb_index_add_all(module, dn, msg->elements, msg->num_elements);
+	ret = ltdb_index_add_all(module, ltdb, dn,
+				 msg->elements, msg->num_elements);
 
 	if (ret != LDB_SUCCESS) {
 		ctx->error = ret;
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index ccad8168a6e..afa0f9e47c3 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -355,6 +355,7 @@ static bool ldb_tdb_single_valued(const struct ldb_schema_attribute *a,
 }
 
 static int ltdb_add_internal(struct ldb_module *module,
+			     struct ltdb_private *ltdb,
 			     const struct ldb_message *msg,
 			     bool check_single_value)
 {
@@ -419,7 +420,7 @@ static int ltdb_add_internal(struct ldb_module *module,
 		return ret;
 	}
 
-	ret = ltdb_index_add_new(module, msg);
+	ret = ltdb_index_add_new(module, ltdb, msg);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -436,6 +437,8 @@ static int ltdb_add(struct ltdb_context *ctx)
 {
 	struct ldb_module *module = ctx->module;
 	struct ldb_request *req = ctx->req;
+	void *data = ldb_module_get_private(module);
+	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	int ret = LDB_SUCCESS;
 
 	ret = ltdb_check_special_dn(module, req->op.add.message);
@@ -449,7 +452,8 @@ static int ltdb_add(struct ltdb_context *ctx)
 		return LDB_ERR_OPERATIONS_ERROR;
 	}
 
-	ret = ltdb_add_internal(module, req->op.add.message, true);
+	ret = ltdb_add_internal(module, ltdb,
+				req->op.add.message, true);
 
 	return ret;
 }
@@ -609,6 +613,7 @@ static int ltdb_msg_add_element(struct ldb_message *msg,
   delete all elements having a specified attribute name
 */
 static int msg_delete_attribute(struct ldb_module *module,
+				struct ltdb_private *ltdb,
 				struct ldb_message *msg, const char *name)
 {
 	unsigned int i;
@@ -621,7 +626,7 @@ static int msg_delete_attribute(struct ldb_module *module,
 	}
 	i = el - msg->elements;
 
-	ret = ltdb_index_del_element(module, msg->dn, el);
+	ret = ltdb_index_del_element(module, ltdb, msg->dn, el);
 	if (ret != LDB_SUCCESS) {
 		return ret;
 	}
@@ -643,6 +648,7 @@ static int msg_delete_attribute(struct ldb_module *module,
   return LDB Error on failure
 */
 static int msg_delete_element(struct ldb_module *module,
+			      struct ltdb_private *ltdb,
 			      struct ldb_message *msg,
 			      const char *name,
 			      const struct ldb_val *val)
@@ -675,10 +681,11 @@ static int msg_delete_element(struct ldb_module *module,
 		}
 		if (matched) {
 			if (el->num_values == 1) {
-				return msg_delete_attribute(module, msg, name);
+				return msg_delete_attribute(module,
+							    ltdb, msg, name);
 			}
 
-			ret = ltdb_index_del_value(module, msg->dn, el, i);
+			ret = ltdb_index_del_value(module, ltdb, msg->dn, el, i);
 			if (ret != LDB_SUCCESS) {
 				return ret;
 			}
@@ -715,6 +722,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 			 struct ldb_request *req)
 {
 	struct ldb_context *ldb = ldb_module_get_ctx(module);
+	void *data = ldb_module_get_private(module);
+	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 	struct ldb_message *msg2;
 	unsigned int i, j;
 	int ret = LDB_SUCCESS, idx;
@@ -800,7 +809,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 					ret = LDB_ERR_OTHER;
 					goto done;
 				}
-				ret = ltdb_index_add_element(module, msg2->dn,
+				ret = ltdb_index_add_element(module, ltdb,
+							     msg2->dn,
 							     el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
@@ -881,7 +891,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				el2->values = vals;
 				el2->num_values += el->num_values;
 
-				ret = ltdb_index_add_element(module, msg2->dn, el);
+				ret = ltdb_index_add_element(module, ltdb,
+							     msg2->dn, el);
 				if (ret != LDB_SUCCESS) {
 					goto done;
 				}
@@ -945,7 +956,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				}
 
 				/* Delete the attribute if it exists in the DB */
-				if (msg_delete_attribute(module, msg2,
+				if (msg_delete_attribute(module, ltdb,
+							 msg2,
 							 el->name) != 0) {
 					ret = LDB_ERR_OTHER;
 					goto done;
@@ -958,7 +970,8 @@ int ltdb_modify_internal(struct ldb_module *module,
 				goto done;
 			}
 
-			ret = ltdb_index_add_element(module, msg2->dn, el);
+			ret = ltdb_index_add_element(module, ltdb,
+						     msg2->dn, el);
 			if (ret != LDB_SUCCESS) {
 				goto done;
 			}
@@ -974,7 +987,9 @@ int ltdb_modify_internal(struct ldb_module *module,
 
 			if (msg->elements[i].num_values == 0) {
 				/* Delete the whole attribute */
-				ret = msg_delete_attribute(module, msg2,
+				ret = msg_delete_attribute(module,
+							   ltdb,
+							   msg2,
 							   msg->elements[i].name);
 				if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
 				    control_permissive) {
@@ -991,6 +1006,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 				/* Delete specified values from an attribute */
 				for (j=0; j < msg->elements[i].num_values; j++) {
 					ret = msg_delete_element(module,
+								 ltdb,
 							         msg2,
 							         msg->elements[i].name,
 							         &msg->elements[i].values[j]);
@@ -1142,7 +1158,7 @@ static int ltdb_rename(struct ltdb_context *ctx)
 	 * deleted attributes. We could go through all elements but that's
 	 * maybe not the most efficient way
 	 */
-	ret = ltdb_add_internal(module, msg, false);
+	ret = ltdb_add_internal(module, ltdb, msg, false);
 
 	talloc_free(msg);
 
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index a391606dd16..7871cbcb6d6 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -82,13 +82,21 @@ int ltdb_check_at_attributes_values(const struct ldb_val *value);
 struct ldb_parse_tree;
 
 int ltdb_search_indexed(struct ltdb_context *ctx, uint32_t *);
-int ltdb_index_add_new(struct ldb_module *module, const struct ldb_message *msg);
+int ltdb_index_add_new(struct ldb_module *module,
+		       struct ltdb_private *ltdb,
+		       const struct ldb_message *msg);
 int ltdb_index_delete(struct ldb_module *module, const struct ldb_message *msg);
-int ltdb_index_del_element(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el);
-int ltdb_index_add_element(struct ldb_module *module, struct ldb_dn *dn, 
+int ltdb_index_add_element(struct ldb_module *module,
+			   struct ltdb_private *ltdb,
+			   struct ldb_dn *dn,
 			   struct ldb_message_element *el);
-int ltdb_index_del_value(struct ldb_module *module, struct ldb_dn *dn,
+int ltdb_index_del_value(struct ldb_module *module,
+			 struct ltdb_private *ltdb,
+			 struct ldb_dn *dn,
 			 struct ldb_message_element *el, unsigned int v_idx);
 int ltdb_reindex(struct ldb_module *module);
 int ltdb_index_transaction_start(struct ldb_module *module);
-- 
2.11.0


From c65f7fa92ee912337ec1b9d7db97d2de51e9a690 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 18 Dec 2017 16:22:01 +1300
Subject: [PATCH 2/6] ldb: Intersect the index from SCOPE_ONELEVEL with the
 index for the search expression

This helps ensure we do not have to scan all objects at this level
which could be very many (one per DNS zone entry).

However, due to the O(n*m) behaviour in list_intersect() for ldb
1.2 and earlier, we only do this for small numbers of matches on the
filter tree.

This behaviour will only be for ldb 1.2 and will not be kept
long-term in LDB, versions 1.3.1 and above will instead only
intersect when the GUID index is in use.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
(adapted from commit 048ee83cf80fcdfb33d9c1630a9a127fa73af4d3)
---
 lib/ldb/ldb_tdb/ldb_index.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c
index ddcf0124dab..56ecf935eb6 100644
--- a/lib/ldb/ldb_tdb/ldb_index.c
+++ b/lib/ldb/ldb_tdb/ldb_index.c
@@ -1075,6 +1075,7 @@ static void ltdb_dn_list_remove_duplicates(struct dn_list *list)
 */
 int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 {
+	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
 	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(ac->module), struct ltdb_private);
 	struct dn_list *dn_list;
 	int ret;
@@ -1109,6 +1110,8 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 		break;
 
 	case LDB_SCOPE_ONELEVEL:
+	{
+		struct dn_list *idx_one_tree_list = NULL;
 		if (!ltdb->cache->one_level_indexes) {
 			talloc_free(dn_list);
 			return LDB_ERR_OPERATIONS_ERROR;
@@ -1118,8 +1121,54 @@ int ltdb_search_indexed(struct ltdb_context *ac, uint32_t *match_count)
 			talloc_free(dn_list);
 			return ret;
 		}
-		break;
 
+		/*
+		 * If we have too many matches, also try the filter
+		 * tree and do index work there
+		 *
+		 * We only do this in the GUID index mode, which is
+		 * O(n*log(m)) otherwise the intersection below will
+		 * be too costly at O(n*m).
+		 */
+		idx_one_tree_list
+			= talloc_zero(ac, struct dn_list);
+		if (idx_one_tree_list == NULL) {
+			return ldb_module_oom(ac->module);
+		}
+		
+		if (!ltdb->cache->attribute_indexes) {
+			talloc_free(idx_one_tree_list);
+			talloc_free(dn_list);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		/*
+		 * Here we load the index for the tree.
+		 */
+		ret = ltdb_index_dn(ac->module, ltdb, ac->tree,
+				    idx_one_tree_list);
+		if (ret != LDB_SUCCESS) {
+			talloc_free(idx_one_tree_list);
+			talloc_free(dn_list);
+			return ret;
+		}
+
+		/* 
+		 * We have to avoid the O(n*m) behaviour here blowing
+		 * up, so we only intersect the lists if it will
+		 * really help
+		 */
+		if (idx_one_tree_list->count < 10) {
+			if (!list_intersect(ldb, ltdb,
+					    dn_list, idx_one_tree_list)) {
+				talloc_free(idx_one_tree_list);
+				talloc_free(dn_list);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+		} else {
+			talloc_free(idx_one_tree_list);
+		}
+		break;
+	}
 	case LDB_SCOPE_SUBTREE:
 	case LDB_SCOPE_DEFAULT:
 		if (!ltdb->cache->attribute_indexes) {
-- 
2.11.0


From 2d390f2d5a6d374759b3aa76006408652e4bc2e7 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 18 Dec 2017 10:14:31 +1300
Subject: [PATCH 3/6] ldb: Release 1.2.3

 - Intersect the index from SCOPE_ONELEVEL with the index for the search expression

    This helps ensure we do not have to scan all objects at this level
    which could be very many (one per DNS zone entry).

    However, due to the O(n*m) behaviour in the LDB index code
    we only do this for small numbers of matches on the
    filter tree.

    This behaviour will only be for ldb 1.2 and will not be kept
    long-term in LDB, versions 1.3.1 and above will instead only
    intersect when the more efficient GUID index is in use.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 lib/ldb/ABI/ldb-1.2.3.sigs            | 277 ++++++++++++++++++++++++++++++++++
 lib/ldb/ABI/pyldb-util-1.2.3.sigs     |   2 +
 lib/ldb/ABI/pyldb-util.py3-1.2.3.sigs |   2 +
 lib/ldb/wscript                       |   2 +-
 4 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100644 lib/ldb/ABI/ldb-1.2.3.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util-1.2.3.sigs
 create mode 100644 lib/ldb/ABI/pyldb-util.py3-1.2.3.sigs

diff --git a/lib/ldb/ABI/ldb-1.2.3.sigs b/lib/ldb/ABI/ldb-1.2.3.sigs
new file mode 100644
index 00000000000..9dc61cda019
--- /dev/null
+++ b/lib/ldb/ABI/ldb-1.2.3.sigs
@@ -0,0 +1,277 @@
+ldb_add: int (struct ldb_context *, const struct ldb_message *)
+ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *)
+ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...)
+ldb_attr_casefold: char *(TALLOC_CTX *, const char *)
+ldb_attr_dn: int (const char *)
+ldb_attr_in_list: int (const char * const *, const char *)
+ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *)
+ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *)
+ldb_base64_decode: int (char *)
+ldb_base64_encode: char *(TALLOC_CTX *, const char *, int)
+ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *)
+ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val)
+ldb_binary_encode_string: char *(TALLOC_CTX *, const char *)
+ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *)
+ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t)
+ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t)
+ldb_check_critical_controls: int (struct ldb_control **)
+ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *)
+ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **)
+ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *)
+ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *)
+ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_debug_add: void (struct ldb_context *, const char *, ...)
+ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level)
+ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...)
+ldb_delete: int (struct ldb_context *, struct ldb_dn *)
+ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...)
+ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *)
+ldb_dn_check_special: bool (struct ldb_dn *, const char *)
+ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val)
+ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *)
+ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *)
+ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *)
+ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *)
+ldb_dn_get_casefold: const char *(struct ldb_dn *)
+ldb_dn_get_comp_num: int (struct ldb_dn *)
+ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int)
+ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int)
+ldb_dn_get_extended_comp_num: int (struct ldb_dn *)
+ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *)
+ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int)
+ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *)
+ldb_dn_get_linearized: const char *(struct ldb_dn *)
+ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *)
+ldb_dn_get_rdn_name: const char *(struct ldb_dn *)
+ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *)
+ldb_dn_has_extended: bool (struct ldb_dn *)
+ldb_dn_is_null: bool (struct ldb_dn *)
+ldb_dn_is_special: bool (struct ldb_dn *)
+ldb_dn_is_valid: bool (struct ldb_dn *)
+ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *)
+ldb_dn_minimise: bool (struct ldb_dn *)
+ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *)
+ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...)
+ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int)
+ldb_dn_remove_extended_components: void (struct ldb_dn *)
+ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *)
+ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val)
+ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *)
+ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *)
+ldb_dn_validate: bool (struct ldb_dn *)
+ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *)
+ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int)
+ldb_errstring: const char *(struct ldb_context *)
+ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **)
+ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_create_perms: unsigned int (struct ldb_context *)
+ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_event_context: struct tevent_context *(struct ldb_context *)
+ldb_get_flags: unsigned int (struct ldb_context *)
+ldb_get_opaque: void *(struct ldb_context *, const char *)
+ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *)
+ldb_global_init: int (void)
+ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *)
+ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *)
+ldb_handle_use_global_event_context: void (struct ldb_handle *)
+ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *)
+ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *)
+ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *)
+ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **)
+ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *)
+ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *)
+ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *)
+ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *)
+ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **)
+ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *)
+ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *)
+ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *)
+ldb_load_modules: int (struct ldb_context *, const char **)
+ldb_map_add: int (struct ldb_module *, struct ldb_request *)
+ldb_map_delete: int (struct ldb_module *, struct ldb_request *)
+ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *)
+ldb_map_modify: int (struct ldb_module *, struct ldb_request *)
+ldb_map_rename: int (struct ldb_module *, struct ldb_request *)
+ldb_map_search: int (struct ldb_module *, struct ldb_request *)
+ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope)
+ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *)
+ldb_match_msg_objectclass: int (const struct ldb_message *, const char *)
+ldb_mod_register_control: int (struct ldb_module *, const char *)
+ldb_modify: int (struct ldb_context *, const struct ldb_message *)
+ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *)
+ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **)
+ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int)
+ldb_module_flags: uint32_t (struct ldb_context *)
+ldb_module_get_ctx: struct ldb_context *(struct ldb_module *)
+ldb_module_get_name: const char *(struct ldb_module *)
+ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *)
+ldb_module_get_private: void *(struct ldb_module *)
+ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *)
+ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **)
+ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *)
+ldb_module_next: struct ldb_module *(struct ldb_module *)
+ldb_module_popt_options: struct poptOption **(struct ldb_context *)
+ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **)
+ldb_module_send_referral: int (struct ldb_request *, char *)
+ldb_module_set_next: void (struct ldb_module *, struct ldb_module *)
+ldb_module_set_private: void (struct ldb_module *, void *)
+ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type)
+ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_modules_load: int (const char *, const char *)
+ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int)
+ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **)
+ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...)
+ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *)
+ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *)
+ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *)
+ldb_msg_add_string: int (struct ldb_message *, const char *, const char *)
+ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **)
+ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *)
+ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *)
+ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *)
+ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *)
+ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **)
+ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *)
+ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *)
+ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *)
+ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double)
+ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int)
+ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t)
+ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *)
+ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int)
+ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t)
+ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t)
+ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t)
+ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *)
+ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *)
+ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *)
+ldb_msg_new: struct ldb_message *(TALLOC_CTX *)
+ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **)
+ldb_msg_remove_attr: void (struct ldb_message *, const char *)
+ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *)
+ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *)
+ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *)
+ldb_msg_sort_elements: void (struct ldb_message *)
+ldb_next_del_trans: int (struct ldb_module *)
+ldb_next_end_trans: int (struct ldb_module *)
+ldb_next_init: int (struct ldb_module *)
+ldb_next_prepare_commit: int (struct ldb_module *)
+ldb_next_read_lock: int (struct ldb_module *)
+ldb_next_read_unlock: int (struct ldb_module *)
+ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_request: int (struct ldb_module *, struct ldb_request *)
+ldb_next_start_trans: int (struct ldb_module *)
+ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
+ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
+ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
+ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *)
+ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *)
+ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *)
+ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t)
+ldb_register_backend: int (const char *, ldb_connect_fn, bool)
+ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *)
+ldb_register_hook: int (ldb_hook_fn)
+ldb_register_module: int (const struct ldb_module_ops *)
+ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *)
+ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *)
+ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *)
+ldb_req_get_custom_flags: uint32_t (struct ldb_request *)
+ldb_req_is_untrusted: bool (struct ldb_request *)
+ldb_req_location: const char *(struct ldb_request *)
+ldb_req_mark_trusted: void (struct ldb_request *)
+ldb_req_mark_untrusted: void (struct ldb_request *)
+ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t)
+ldb_req_set_location: void (struct ldb_request *, const char *)
+ldb_request: int (struct ldb_context *, struct ldb_request *)
+ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_done: int (struct ldb_request *, int)
+ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *)
+ldb_request_get_status: int (struct ldb_request *)
+ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *)
+ldb_request_set_state: void (struct ldb_request *, int)
+ldb_reset_err_string: void (struct ldb_context *)
+ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***)
+ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *)
+ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *)
+ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *)
+ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *)
+ldb_schema_attribute_remove: void (struct ldb_context *, const char *)
+ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int)
+ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *)
+ldb_schema_set_override_indexlist: void (struct ldb_context *, bool)
+ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...)
+ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *)
+ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *)
+ldb_set_create_perms: void (struct ldb_context *, unsigned int)
+ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *)
+ldb_set_debug_stderr: int (struct ldb_context *)
+ldb_set_default_dns: void (struct ldb_context *)
+ldb_set_errstring: void (struct ldb_context *, const char *)
+ldb_set_event_context: void (struct ldb_context *, struct tevent_context *)
+ldb_set_flags: void (struct ldb_context *, unsigned int)
+ldb_set_modules_dir: void (struct ldb_context *, const char *)
+ldb_set_opaque: int (struct ldb_context *, const char *, void *)
+ldb_set_require_private_event_context: void (struct ldb_context *)
+ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int)
+ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *)
+ldb_set_utf8_default: void (struct ldb_context *)
+ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t))
+ldb_setup_wellknown_attributes: int (struct ldb_context *)
+ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *)
+ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *)
+ldb_strerror: const char *(int)
+ldb_string_to_time: time_t (const char *)
+ldb_string_utc_to_time: time_t (const char *)
+ldb_timestring: char *(TALLOC_CTX *, time_t)
+ldb_timestring_utc: char *(TALLOC_CTX *, time_t)
+ldb_transaction_cancel: int (struct ldb_context *)
+ldb_transaction_cancel_noerr: int (struct ldb_context *)
+ldb_transaction_commit: int (struct ldb_context *)
+ldb_transaction_prepare_commit: int (struct ldb_context *)
+ldb_transaction_start: int (struct ldb_context *)
+ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
+ldb_unpack_data_only_attr_list: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int *)
+ldb_unpack_data_only_attr_list_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, const char * const *, unsigned int, unsigned int, unsigned int *)
+ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
+ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
+ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
+ldb_val_string_cmp: int (const struct ldb_val *, const char *)
+ldb_val_to_time: int (const struct ldb_val *, time_t *)
+ldb_valid_attr_name: int (const char *)
+ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list)
+ldb_wait: int (struct ldb_handle *, enum ldb_wait_type)
diff --git a/lib/ldb/ABI/pyldb-util-1.2.3.sigs b/lib/ldb/ABI/pyldb-util-1.2.3.sigs
new file mode 100644
index 00000000000..74d6719d2bc
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util-1.2.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/ABI/pyldb-util.py3-1.2.3.sigs b/lib/ldb/ABI/pyldb-util.py3-1.2.3.sigs
new file mode 100644
index 00000000000..74d6719d2bc
--- /dev/null
+++ b/lib/ldb/ABI/pyldb-util.py3-1.2.3.sigs
@@ -0,0 +1,2 @@
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **)
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index bd17b7b9edc..5ea52317d4d 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'ldb'
-VERSION = '1.2.2'
+VERSION = '1.2.3'
 
 blddir = 'bin'
 
-- 
2.11.0


From 95fe3227031450d1e9d89cf6e9e165679e234fc9 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 15 Dec 2017 11:40:28 +1300
Subject: [PATCH 4/6] dns_server: Do not look for a wildcard for @

This query is made for every record returned via BIND9 DLZ.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index 217e65b39f4..093898361d0 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -547,6 +547,16 @@ WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
 		return DNS_ERR(NAME_ERROR);
 	}
 
+	/* Don't look for a wildcard for @ */
+	if (name->length == 1 && name->data[0] == '@') {
+		return dns_common_lookup(samdb,
+					 mem_ctx,
+					 dn,
+					 records,
+					 num_records,
+					 NULL);
+	}
+
 	werr =  dns_name_check(
 			mem_ctx,
 			strlen((const char*)name->data),
-- 
2.11.0


From 3474f80b854499f68a937d539a4b8d3ec7f6d066 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 15 Dec 2017 12:30:50 +1300
Subject: [PATCH 5/6] dns_server: Do the exact match query first, then do the
 wildcard lookup

The wildcard lookup is SCOPE_ONELEVEL which in current ldb will load the full index for that zone.

This is inefficient as we do not currently intersect that index with the
index on DN=

Not that a not-found and wildcard response will still go via the ONELEVEL
index for now so this only helps for correct, directly matching queries.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index 093898361d0..af6eb9ba7a6 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -565,6 +565,20 @@ WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
 		return werr;
 	}
 
+	/* 
+	 * Do a point search first, then fall back to a wildcard
+	 * lookup if it does not exist
+	 */
+	werr = dns_common_lookup(samdb,
+				 mem_ctx,
+				 dn,
+				 records,
+				 num_records,
+				 NULL);
+	if (!W_ERROR_EQUAL(werr, WERR_DNS_ERROR_NAME_DOES_NOT_EXIST)) {
+		return werr;
+	}
+	
 	ret = dns_wildcard_lookup(samdb, mem_ctx, dn, &msg);
 	if (ret == LDB_ERR_OPERATIONS_ERROR) {
 		return DNS_ERR(SERVER_FAILURE);
-- 
2.11.0


From a396f27e7def02c6e1e43b2163eaef4b6d6aa5de Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Mon, 18 Dec 2017 16:22:23 +1300
Subject: [PATCH 6/6] dns_server: Use the indexed "name" attribute in wildcard
 lookup

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13191

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/dns_server/dnsserver_common.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c
index af6eb9ba7a6..38acfff9a00 100644
--- a/source4/dns_server/dnsserver_common.c
+++ b/source4/dns_server/dnsserver_common.c
@@ -305,6 +305,8 @@ static unsigned int number_of_labels(const struct ldb_val *name) {
  *
  * x.y.z -> (|(name=x.y.z)(name=\2a.y.z)(name=\2a.z)(name=\2a))
  *
+ * The attribute 'name' is used as this is what the LDB index is on
+ *
  * Returns NULL if unable to build the query.
  *
  * The first component of the DN is assumed to be the name being looked up
@@ -318,7 +320,7 @@ static struct ldb_parse_tree *build_wildcard_query(
 {
 	const struct ldb_val *name = NULL;            /* The DNS name being
 							 queried */
-	const char *attr = NULL;                      /* The attribute name */
+	const char *attr = "name";                    /* The attribute name */
 	struct ldb_parse_tree *query = NULL;          /* The constructed query
 							 parse tree*/
 	struct ldb_parse_tree *wildcard_query = NULL; /* The parse tree for the
@@ -326,12 +328,6 @@ static struct ldb_parse_tree *build_wildcard_query(
 							 entries */
 	int labels = 0;         /* The number of labels in the name */
 
-	attr = ldb_dn_get_rdn_name(dn);
-	if (attr == NULL) {
-		DBG_ERR("Unable to get rdn_name\n");
-		return NULL;
-	}
-
 	name = ldb_dn_get_rdn_val(dn);
 	if (name == NULL) {
 		DBG_ERR("Unable to get domain name value\n");
-- 
2.11.0



More information about the samba-technical mailing list