#8808 Investigate how the deref control may help performance
Closed: wontfix 7 months ago by antorres. Opened 3 years ago by rcritten.

Request for enhancement

The dereference control provides a means to collect extra information related to cross-links present in entries returned as part of search responses when using DN for linkage. It's about as close to an SQL JOIN you can get with LDAP but it's just one level deep.

The draft proposal is https://tools.ietf.org/html/draft-masarati-ldap-deref-00

Apparently care needs to be taken when retrieving multiple things as this can exponentially increase the number of objects examined. I have no further details beyond the warning in https://serverfault.com/questions/915765/can-we-get-attributes-of-all-referenced-dns-in-ldap-with-a-single-query

python-ldap and 389-ds support this.

Also relevant is https://pagure.io/389-ds-base/issue/49951


Metadata Update from @pcech:
- Issue set to the milestone: Performance Improvements

2 years ago

We have investigated the usage of the dereference control in IPA. The main scenario for it is when an entry with members associated is pulled, and we later need information about those associated entries. After investigation on how to integrate this improvement with our current set of plugins, we found that the main scenario for this (*group-show) doesn't need it, as the member entries aren't actually pulled from LDAP, but the username is derived from the DN instead. While we should keep this feature in mind for future plugins, there aren't any places in our current codebase were we can take advantage of it.

An example usage is available at: https://github.com/python-ldap/python-ldap/blob/main/Demo/pyasn1/derefcontrol.py

And here's a preliminary diff to integrate it in ipaldap:

diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py
index 531305eaa..eeed811cf 100644
--- a/ipapython/ipaldap.py
+++ b/ipapython/ipaldap.py
@@ -40,6 +40,7 @@ import ldap
 import ldap.sasl
 import ldap.filter
 from ldap.controls import SimplePagedResultsControl, GetEffectiveRightsControl
+from ldap.controls.deref import DereferenceControl
 import ldapurl
 import six

@@ -1481,7 +1482,8 @@ class LDAPClient:
     def find_entries(
             self, filter=None, attrs_list=None, base_dn=None,
             scope=ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
-            paged_search=False, get_effective_rights=False):
+            paged_search=False, get_effective_rights=False, dereference_members=False,
+            dereference_attrs=None):
         """
         Return a list of entries and indication of whether the results were
         truncated ([(dn, entry_attrs)], truncated) matching specified search
@@ -1499,6 +1501,8 @@ class LDAPClient:
                            (default unlimited)
         :param paged_search: search using paged results control
         :param get_effective_rights: use GetEffectiveRights control
+        :param dereference_members: use DereferenceControl to dereference member entries
+        :param dereference_attrs: list of attributes to be dereferenced from members

         :raises: errors.NotFound if result set is empty
                                  or base_dn doesn't exist
@@ -1528,6 +1532,11 @@ class LDAPClient:
             attrs_list = [a.lower() for a in set(attrs_list)]

         base_sctrls = []
+
+        if dereference_members and dereference_attrs:
+            dc = DereferenceControl(True, {'member': dereference_attrs})
+            base_sctrls.append(dc)
+
         if get_effective_rights:
             base_sctrls.append(self.__get_effective_rights_control())

@@ -1557,8 +1566,8 @@ class LDAPClient:
                         sizelimit=size_limit
                     )
                     while True:
-                        result = self.conn.result3(id, 0)
-                        objtype, res_list, _res_id, res_ctrls = result
+                        result = self.conn.result4(id, 0, add_ctrls=1)
+                        objtype, res_list, _res_id, res_ctrls, _res_name, _res_value = result
                         if objtype == ldap.RES_SEARCH_RESULT:
                             break
                         res_list = self._convert_result(res_list)

Metadata Update from @antorres:
- Issue close_status updated to: wontfix
- Issue status updated to: Closed (was: Open)

7 months ago

Login to comment on this ticket.

Metadata