diff options
author | Fraser Tweedale <ftweedal@redhat.com> | 2016-09-14 19:39:36 +1000 |
---|---|---|
committer | Matthew Harmsen <mharmsen@redhat.com> | 2016-10-10 16:37:13 -0600 |
commit | 02081bef01fd10325a27587221ed076c13de10fa (patch) | |
tree | 8c945b1b6a9a9a10aac1c398161c80978efde4ad /base/server | |
parent | 9043a08bef3723ca218ad7e5dd82be61166b5a1d (diff) | |
download | pki-02081bef01fd10325a27587221ed076c13de10fa.tar.gz pki-02081bef01fd10325a27587221ed076c13de10fa.tar.xz pki-02081bef01fd10325a27587221ed076c13de10fa.zip |
Block reads during reload of LDAP-based profiles
LDAP disconnect (e.g. due to DS restart) causes LDAPProfileSubsystem
to drop all its profiles and reload them. If a profile is read
during this time, e.g. to issue a certificate, it might not have
been reloaded thus causing the operation to fail.
Introduce the AsyncLoader class which allows a consumer to await the
completion of a (re)load, if one is happening. Update the
getProfile and getProfileIds method to use it.
The existing 'initialLoadDone' CountDownLatch for blocking
LDAPProfileSubsystem init until the inital load of profiles is
completed was subsumed by AsyncLoader.
Fixes: https://fedorahosted.org/pki/ticket/2453
NOTE: This patch is ONLY intended for Dogtag 10.4.0 versions and later;
it is NOT intended to be back-ported to Dogtag 10.3.x versions.
Diffstat (limited to 'base/server')
-rw-r--r-- | base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java | 59 |
1 files changed, 41 insertions, 18 deletions
diff --git a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java index 6dea1a0d8..fd5aa64ee 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java +++ b/base/server/cmscore/src/com/netscape/cmscore/profile/LDAPProfileSubsystem.java @@ -20,11 +20,11 @@ package com.netscape.cmscore.profile; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Arrays; +import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.TreeMap; import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; import netscape.ldap.LDAPAttribute; import netscape.ldap.LDAPAttributeSet; @@ -49,6 +49,7 @@ import com.netscape.certsrv.profile.IProfile; import com.netscape.certsrv.profile.IProfileSubsystem; import com.netscape.certsrv.registry.IPluginInfo; import com.netscape.certsrv.registry.IPluginRegistry; +import com.netscape.certsrv.util.AsyncLoader; import com.netscape.cmscore.base.LDAPConfigStore; import com.netscape.cmsutil.ldap.LDAPUtil; @@ -71,10 +72,7 @@ public class LDAPProfileSubsystem /* Set of nsUniqueIds of deleted entries */ private TreeSet<String> deletedNsUniqueIds; - /* Variables to track initial loading of profiles */ - private Integer initialNumProfiles = null; - private int numProfilesLoaded = 0; - private CountDownLatch initialLoadDone = new CountDownLatch(1); + private AsyncLoader loader = new AsyncLoader(); /** * Initializes this subsystem with the given configuration @@ -118,7 +116,7 @@ public class LDAPProfileSubsystem monitor = new Thread(this, "profileChangeMonitor"); monitor.start(); try { - initialLoadDone.await(); + loader.awaitLoadDone(); } catch (InterruptedException e) { CMS.debug("LDAPProfileSubsystem: caught InterruptedException " + "while waiting for initial load of profiles."); @@ -126,6 +124,27 @@ public class LDAPProfileSubsystem CMS.debug("LDAPProfileSubsystem: finished init"); } + public IProfile getProfile(String id) + throws EProfileException { + try { + loader.awaitLoadDone(); + } catch (InterruptedException e) { + CMS.debug("LDAPProfileSubsystem.getProfile: caught InterruptedException " + + "while waiting for profiles to be loaded."); + } + return super.getProfile(id); + } + + public Enumeration<String> getProfileIds() { + try { + loader.awaitLoadDone(); + } catch (InterruptedException e) { + CMS.debug("LDAPProfileSubsystem.getProfile: caught InterruptedException " + + "while waiting for profiles to be loaded."); + } + return super.getProfileIds(); + } + /** * Read the given LDAPEntry into the profile subsystem. */ @@ -395,12 +414,6 @@ public class LDAPProfileSubsystem return "cn=" + id + "," + dn; } - private void checkInitialLoadDone() { - if (initialNumProfiles != null - && numProfilesLoaded >= initialNumProfiles) - initialLoadDone.countDown(); - } - private void ensureProfilesOU(LDAPConnection conn) throws LDAPException { try { conn.search(dn, LDAPConnection.SCOPE_BASE, "(objectclass=*)", null, false); @@ -431,7 +444,6 @@ public class LDAPProfileSubsystem CMS.debug("Profile change monitor: starting."); while (!stopped) { - forgetAllProfiles(); try { conn = dbFactory.getConn(); ensureProfilesOU(conn); @@ -443,16 +455,28 @@ public class LDAPProfileSubsystem LDAPSearchResults results = conn.search( dn, LDAPConnection.SCOPE_SUB, "(objectclass=*)", attrs, false, cons); + + /* Wait until the last possible moment before taking + * the load lock and dropping all profiles, so that + * we can continue to service requests while LDAP is + * down. + * + * Once we reconnect, we need to forget all profiles + * and reload in case some were removed in the + * interim. + */ + loader.startLoading(); + forgetAllProfiles(); + while (!stopped && results.hasMoreElements()) { LDAPEntry entry = results.next(); String[] objectClasses = entry.getAttribute("objectClass").getStringValueArray(); if (Arrays.asList(objectClasses).contains("organizationalUnit")) { - initialNumProfiles = new Integer( + loader.setNumItems(new Integer( entry.getAttribute("numSubordinates") - .getStringValueArray()[0]); - checkInitialLoadDone(); + .getStringValueArray()[0])); continue; } @@ -486,8 +510,7 @@ public class LDAPProfileSubsystem } else { CMS.debug("Profile change monitor: immediate result"); readProfile(entry); - numProfilesLoaded += 1; - checkInitialLoadDone(); + loader.increment(); } } } catch (ELdapException e) { |