From 91f721601a6edaf0d15de2f7cc6991c7492c7653 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 7 May 2019 11:49:25 +0100 Subject: [PATCH] accounts: Use heavy caching to take off load from LDAP server Signed-off-by: Michael Tremer --- src/backend/accounts.py | 54 +++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/backend/accounts.py b/src/backend/accounts.py index dfdebf98..784ddabc 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -49,13 +49,13 @@ class Accounts(Object): return conn - def _query(self, query, attrlist=None, limit=0): + def _query(self, query, attrlist=None, limit=0, search_base=None, scope=None): logging.debug("Performing LDAP query: %s" % query) t = time.time() - results = self.ldap.search_ext_s(self.search_base, ldap.SCOPE_SUBTREE, - query, attrlist=attrlist, sizelimit=limit) + results = self.ldap.search_ext_s(search_base or self.search_base, + scope or ldap.SCOPE_SUBTREE, query, attrlist=attrlist, sizelimit=limit) # Log time it took to perform the query logging.debug("Query took %.2fms" % ((time.time() - t) * 1000.0)) @@ -63,8 +63,47 @@ class Accounts(Object): return results def _search(self, query, attrlist=None, limit=0): - for dn, attrs in self._query(query, attrlist=attrlist, limit=limit): - yield Account(self.backend, dn, attrs) + dns = self._search_dns(query, limit=limit) + + return self._get_accounts_from_dns(dns) + + def _search_dns(self, query, limit=0): + # Query cache + dns = self.memcache.get("accounts:search:%s" % query) + if dns is None: + # Return DNs only for this search query + dns = [] + for dn, attrs in self._query(query, attrlist=["dn"], limit=limit): + dns.append(dn) + + # Cache for 10 min + self.memcache.set("accounts:search:%s" % query, dns, 600) + + return dns + + def _get_accounts_from_dns(self, dns): + for dn in dns: + yield self._get_account_from_dn(dn) + + def _get_account_from_dn(self, dn): + attrs = self.memcache.get("accounts:%s:attrs" % dn) + if attrs is None: + attrs = self._get_attrs(dn) + assert attrs, dn + + # Cache all attributes for 5 min + self.memcache.set("accounts:%s:attrs" % dn, attrs, 300) + + return Account(self.backend, dn, attrs) + + def _get_attrs(self, dn): + """ + Fetches all attributes for the given distinguished name + """ + results = self._query("(objectClass=*)", search_base=dn, limit=1) + + for dn, attrs in results: + return attrs def search(self, query): # Search for exact matches @@ -105,8 +144,6 @@ class Accounts(Object): def get_by_mail(self, mail): return self._search_one("(&(objectClass=inetOrgPerson)(mail=%s))" % mail) - find = get_by_uid - def find_account(self, s): account = self.get_by_uid(s) if account: @@ -257,6 +294,9 @@ class Account(Object): # Run modify operation self.ldap.modify_s(self.dn, modlist) + # Delete cached attributes + self.memcache.delete("accounts:%s:attrs") + def _set(self, key, values): current = self._get(key) -- 2.47.3