From a79aa3ddbd25b8c7c0abc6c8d5a00c7ed27dd81d Mon Sep 17 00:00:00 2001
From: abobrov <abobrov@localhost>
Date: Sun, 02 Dec 2007 17:54:15 +0000
Subject: [PATCH] - [Issue 2007]  generic mechanism for using mulitple caches. - [Issue 2049]  dsconfig is unable to configure the entry cache.

---
 opends/src/server/org/opends/server/core/EntryCacheConfigManager.java |  279 ++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 211 insertions(+), 68 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java b/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
index 710b430..b0eede9 100644
--- a/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
+++ b/opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
@@ -31,8 +31,11 @@
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import org.opends.server.admin.ClassPropertyDefinition;
 import org.opends.server.admin.server.ConfigurationAddListener;
@@ -44,13 +47,18 @@
 import org.opends.server.admin.std.meta.EntryCacheCfgDefn;
 import org.opends.server.api.EntryCache;
 import org.opends.server.config.ConfigException;
-import org.opends.server.extensions.DefaultEntryCache;
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.ConfigChangeResult;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.InitializationException;
 import org.opends.server.types.ResultCode;
 import org.opends.messages.MessageBuilder;
+import org.opends.server.admin.std.server.EntryCacheMonitorProviderCfg;
+import org.opends.server.config.ConfigConstants;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.extensions.DefaultEntryCache;
+import org.opends.server.monitors.EntryCacheMonitorProvider;
+import org.opends.server.types.DN;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -61,8 +69,8 @@
 
 /**
  * This class defines a utility that will be used to manage the configuration
- * for the Directory Server entry cache.  Only a single entry cache may be
- * defined, but if it is absent or disabled, then a default cache will be used.
+ * for the Directory Server entry cache.  The default entry cache is always
+ * enabled.
  */
 public class EntryCacheConfigManager
        implements
@@ -75,13 +83,21 @@
    */
   private static final DebugTracer TRACER = getTracer();
 
-  // The current entry cache registered in the server
-  private EntryCache _entryCache = null;
+  // The default entry cache.
+  private DefaultEntryCache _defaultEntryCache = null;
 
-  // The default entry cache to use when no entry cache has been configured
-  // or when the configured entry cache could not be initialized.
-  private EntryCache _defaultEntryCache = null;
+  // The entry cache order map sorted by the cache level.
+  private static SortedMap<Integer, EntryCache<? extends
+    EntryCacheCfg>> cacheOrderMap = new TreeMap<Integer,
+    EntryCache<? extends EntryCacheCfg>>();
 
+  // The entry cache name to level map.
+  private static HashMap<String, Integer>
+    cacheNameToLevelMap = new HashMap<String, Integer>();
+
+  // Global entry cache monitor provider name.
+  private static final String
+    DEFAULT_ENTRY_CACHE_MONITOR_PROVIDER = "Entry Caches";
 
   /**
    * Creates a new instance of this entry cache config manager.
@@ -127,8 +143,8 @@
   /**
    * Initializes the configuration associated with the Directory Server entry
    * cache.  This should only be called at Directory Server startup.  If an
-   * error occurs, then a message will be logged and the default entry cache
-   * will be installed.
+   * error occurs, then a message will be logged for each entry cache that is
+   * failed to initialize.
    *
    * @throws  ConfigException  If a configuration problem causes the entry
    *                           cache initialization process to fail.
@@ -152,34 +168,61 @@
     rootConfiguration.addEntryCacheAddListener(this);
     rootConfiguration.addEntryCacheDeleteListener(this);
 
-    // If the entry cache configuration is not present then keep the
-    // default entry cache already installed.
-    if (!rootConfiguration.hasEntryCache())
+    // Get the base entry cache configuration entry.
+    ConfigEntry entryCacheBase;
+    try {
+      DN configEntryDN = DN.decode(ConfigConstants.DN_ENTRY_CACHE_BASE);
+      entryCacheBase   = DirectoryServer.getConfigEntry(configEntryDN);
+    } catch (Exception e) {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      logError(WARN_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY.get());
+      return;
+    }
+
+    // If the configuration base entry is null, then assume it doesn't exist.
+    // At least that entry must exist in the configuration, even if there are
+    // no entry cache defined below it.
+    if (entryCacheBase == null)
     {
       logError(WARN_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY.get());
       return;
     }
 
-    // Get the entry cache configuration.
-    EntryCacheCfg configuration = rootConfiguration.getEntryCache();
-
-    // At this point, we have a configuration entry. Register a change
-    // listener with it so we can be notified of changes to it over time.
-    configuration.addChangeListener(this);
-
-    // Initialize the entry cache.
-    if (configuration.isEnabled())
+    // Initialize every entry cache configured.
+    for (String cacheName : rootConfiguration.listEntryCaches())
     {
-      // Load the entry cache implementation class and install the entry
-      // cache with the server.
-      String className = configuration.getJavaClass();
-      try
-      {
-        loadAndInstallEntryCache (className);
+      // Get the entry cache configuration.
+      EntryCacheCfg configuration = rootConfiguration.getEntryCache(cacheName);
+
+      // At this point, we have a configuration entry. Register a change
+      // listener with it so we can be notified of changes to it over time.
+      configuration.addChangeListener(this);
+
+      // Check if there is another entry cache installed at the same level.
+      if (!cacheOrderMap.isEmpty()) {
+        if (cacheOrderMap.containsKey(configuration.getCacheLevel())) {
+          // Log error and skip this cache.
+          logError(ERR_CONFIG_ENTRYCACHE_CONFIG_LEVEL_NOT_ACCEPTABLE.get(
+            String.valueOf(configuration.dn()),
+            configuration.getCacheLevel()));
+          continue;
+        }
       }
-      catch (InitializationException ie)
-      {
-        logError(ie.getMessageObject());
+
+      // Initialize the entry cache.
+      if (configuration.isEnabled()) {
+        // Load the entry cache implementation class and install the entry
+        // cache with the server.
+        String className = configuration.getJavaClass();
+        try {
+          loadAndInstallEntryCache(className, configuration);
+        } catch (InitializationException ie) {
+          logError(ie.getMessageObject());
+        }
       }
     }
   }
@@ -207,6 +250,23 @@
       status = false;
     }
 
+    if (!cacheOrderMap.isEmpty() && !cacheNameToLevelMap.isEmpty() &&
+      (cacheNameToLevelMap.get(
+       configuration.dn().toNormalizedString()) != null)) {
+      int currentCacheLevel = cacheNameToLevelMap.get(
+        configuration.dn().toNormalizedString());
+
+      // Check if there any existing cache at the same level.
+      if ((currentCacheLevel != configuration.getCacheLevel()) &&
+        (cacheOrderMap.containsKey(configuration.getCacheLevel()))) {
+        unacceptableReasons.add(
+          ERR_CONFIG_ENTRYCACHE_CONFIG_LEVEL_NOT_ACCEPTABLE.get(
+            String.valueOf(configuration.dn()),
+            configuration.getCacheLevel()));
+        status = false;
+      }
+    }
+
     return status;
   }
 
@@ -218,34 +278,64 @@
       EntryCacheCfg configuration
       )
   {
+    EntryCache<? extends EntryCacheCfg> entryCache = null;
+
+    // If we this entry cache is already installed and active it
+    // should be present in the cache maps, if so use it.
+    if (!cacheOrderMap.isEmpty() && !cacheNameToLevelMap.isEmpty() &&
+      (cacheNameToLevelMap.get(
+       configuration.dn().toNormalizedString()) != null)) {
+      int currentCacheLevel = cacheNameToLevelMap.get(
+        configuration.dn().toNormalizedString());
+      entryCache = cacheOrderMap.get(currentCacheLevel);
+
+      // Check if the existing cache just shifted its level.
+      if (currentCacheLevel != configuration.getCacheLevel()) {
+        // Update the maps then.
+        cacheOrderMap.remove(currentCacheLevel);
+        cacheOrderMap.put(configuration.getCacheLevel(), entryCache);
+        cacheNameToLevelMap.put(configuration.dn().toNormalizedString(),
+          configuration.getCacheLevel());
+      }
+    }
+
     // Returned result.
     ConfigChangeResult changeResult = new ConfigChangeResult(
         ResultCode.SUCCESS, false, new ArrayList<Message>()
         );
 
-    // If the new configuration has the entry cache disabled, then install
-    // the default entry cache with the server.
-    if (! configuration.isEnabled())
+    // If an entry cache was installed then remove it.
+    if (!configuration.isEnabled())
     {
-      DirectoryServer.setEntryCache (_defaultEntryCache);
-
-      // If an entry cache was installed then clean it.
-      if (_entryCache != null)
+      configuration.getCacheLevel();
+      if (entryCache != null)
       {
-        _entryCache.finalizeEntryCache();
-        _entryCache = null;
+        EntryCacheMonitorProvider monitor = entryCache.getEntryCacheMonitor();
+        if (monitor != null)
+        {
+          String instanceName = toLowerCase(monitor.getMonitorInstanceName());
+          DirectoryServer.deregisterMonitorProvider(instanceName);
+          monitor.finalizeMonitorProvider();
+          entryCache.setEntryCacheMonitor(null);
+        }
+        entryCache.finalizeEntryCache();
+        cacheOrderMap.remove(configuration.getCacheLevel());
+        entryCache = null;
       }
       return changeResult;
     }
 
+    // Push any changes made to the cache order map.
+    _defaultEntryCache.setCacheOrder(cacheOrderMap);
+
     // At this point, new configuration is enabled...
     // If the current entry cache is already enabled then we don't do
     // anything unless the class has changed in which case we should
     // indicate that administrative action is required.
     String newClassName = configuration.getJavaClass();
-    if (_entryCache !=null)
+    if ( entryCache != null)
     {
-      String curClassName = _entryCache.getClass().getName();
+      String curClassName = entryCache.getClass().getName();
       boolean classIsNew = (! newClassName.equals (curClassName));
       if (classIsNew)
       {
@@ -258,7 +348,7 @@
     // Instantiate the new class and initalize it.
     try
     {
-      loadAndInstallEntryCache (newClassName);
+      loadAndInstallEntryCache (newClassName, configuration);
     }
     catch (InitializationException ie)
     {
@@ -282,6 +372,18 @@
     // returned status -- all is fine by default
     boolean status = true;
 
+    // Check if there is another entry cache installed at the same level.
+    if (!cacheOrderMap.isEmpty()) {
+      if (cacheOrderMap.containsKey(configuration.getCacheLevel())) {
+        unacceptableReasons.add(
+          ERR_CONFIG_ENTRYCACHE_CONFIG_LEVEL_NOT_ACCEPTABLE.get(
+            String.valueOf(configuration.dn()),
+            configuration.getCacheLevel()));
+        status = false;
+        return status;
+      }
+    }
+
     if (configuration.isEnabled())
     {
       // Get the name of the class and make sure we can instantiate it as
@@ -325,7 +427,7 @@
       String className = configuration.getJavaClass();
       try
       {
-        loadAndInstallEntryCache (className);
+        loadAndInstallEntryCache (className, configuration);
       }
       catch (InitializationException ie)
       {
@@ -361,18 +463,38 @@
       EntryCacheCfg configuration
       )
   {
+    EntryCache<? extends EntryCacheCfg> entryCache = null;
+
+    // If we this entry cache is already installed and active it
+    // should be present in the current cache order map, use it.
+    if (!cacheOrderMap.isEmpty()) {
+      entryCache = cacheOrderMap.get(configuration.getCacheLevel());
+    }
+
     // Returned result.
     ConfigChangeResult changeResult = new ConfigChangeResult(
         ResultCode.SUCCESS, false, new ArrayList<Message>()
         );
 
-    // If the entry cache was installed then replace it with the
-    // default entry cache, and clean it.
-    if (_entryCache != null)
+    // If the entry cache was installed then remove it.
+    if (entryCache != null)
     {
-      DirectoryServer.setEntryCache (_defaultEntryCache);
-      _entryCache.finalizeEntryCache();
-      _entryCache = null;
+      EntryCacheMonitorProvider monitor = entryCache.getEntryCacheMonitor();
+      if (monitor != null)
+      {
+        String instanceName = toLowerCase(monitor.getMonitorInstanceName());
+        DirectoryServer.deregisterMonitorProvider(instanceName);
+        monitor.finalizeMonitorProvider();
+        entryCache.setEntryCacheMonitor(null);
+      }
+      entryCache.finalizeEntryCache();
+      cacheOrderMap.remove(configuration.getCacheLevel());
+      cacheNameToLevelMap.remove(configuration.dn().toNormalizedString());
+
+      // Push any changes made to the cache order map.
+      _defaultEntryCache.setCacheOrder(cacheOrderMap);
+
+      entryCache = null;
     }
 
     return changeResult;
@@ -394,34 +516,47 @@
    *                                   to initialize the entry cache.
    */
   private void loadAndInstallEntryCache(
-    String        className
+    String        className,
+    EntryCacheCfg configuration
     )
     throws InitializationException
   {
-    EntryCacheCfg configuration;
-
     // Get the root configuration object.
     ServerManagementContext managementContext =
       ServerManagementContext.getInstance();
     RootCfg rootConfiguration =
       managementContext.getRootConfiguration();
 
-    // Get the entry cache configuration.
-    try {
-      configuration = rootConfiguration.getEntryCache();
-    } catch (ConfigException ce) {
-      Message message = ERR_CONFIG_ENTRYCACHE_CANNOT_INITIALIZE_CACHE.get(
-        className, (ce.getCause() != null ? ce.getCause().getMessage() :
-          stackTraceToSingleLineString(ce)));
-      throw new InitializationException(message, ce);
-    }
-
     // Load the entry cache class...
-    EntryCache entryCache = loadEntryCache (className, configuration, true);
+    EntryCache<? extends EntryCacheCfg> entryCache =
+      loadEntryCache (className, configuration, true);
 
     // ... and install the entry cache in the server.
-    DirectoryServer.setEntryCache(entryCache);
-    _entryCache = entryCache;
+
+    // Add this entry cache to the current cache config maps.
+    cacheOrderMap.put(configuration.getCacheLevel(), entryCache);
+    cacheNameToLevelMap.put(configuration.dn().toNormalizedString(),
+      configuration.getCacheLevel());
+
+    // Push any changes made to the cache order map.
+    _defaultEntryCache.setCacheOrder(cacheOrderMap);
+
+    // Install and register the monitor for this cache.
+    EntryCacheMonitorProvider monitor = new EntryCacheMonitorProvider(
+        configuration.definition().getUserFriendlyName().toString(),
+        entryCache);
+    try {
+      monitor.initializeMonitorProvider((EntryCacheMonitorProviderCfg)
+        rootConfiguration.getMonitorProvider(
+        DEFAULT_ENTRY_CACHE_MONITOR_PROVIDER));
+    } catch (ConfigException ce) {
+      // ConfigException here means that either the entry cache monitor
+      // config entry is not present or the monitor is not enabled. In
+      // either case that means no monitor provider for this cache.
+      return;
+    }
+    entryCache.setEntryCacheMonitor(monitor);
+    DirectoryServer.registerMonitorProvider(monitor);
   }
 
 
@@ -448,6 +583,14 @@
     )
     throws InitializationException
   {
+    EntryCache entryCache = null;
+
+    // If we this entry cache is already installed and active it
+    // should be present in the current cache order map, use it.
+    if (!cacheOrderMap.isEmpty()) {
+      entryCache = cacheOrderMap.get(configuration.getCacheLevel());
+    }
+
     try
     {
       EntryCacheCfgDefn                   definition;
@@ -461,10 +604,10 @@
 
       // If there is some entry cache instance already initialized work with
       // it instead of creating a new one unless explicit init is requested.
-      if (initialize || (_entryCache == null)) {
+      if (initialize || (entryCache == null)) {
         cache = (EntryCache<? extends EntryCacheCfg>) cacheClass.newInstance();
       } else {
-        cache = (EntryCache<? extends EntryCacheCfg>) _entryCache;
+        cache = (EntryCache<? extends EntryCacheCfg>) entryCache;
       }
 
       if (initialize)

--
Gitblit v1.10.0