opends/resource/config/config.ldif
@@ -487,13 +487,37 @@ ds-cfg-listen-port: 1689 ds-cfg-ssl-cert-nickname: server-cert dn: cn=Entry Cache,cn=config dn: cn=Entry Caches,cn=config objectClass: top objectClass: ds-cfg-branch cn: Entry Caches dn: cn=Soft Reference,cn=Entry Caches,cn=config objectClass: top objectClass: ds-cfg-entry-cache objectClass: ds-cfg-soft-reference-entry-cache cn: Entry Cache ds-cfg-java-class: org.opends.server.extensions.SoftReferenceEntryCache cn: Soft Reference ds-cfg-enabled: false ds-cfg-cache-level: 1 ds-cfg-java-class: org.opends.server.extensions.SoftReferenceEntryCache dn: cn=FIFO,cn=Entry Caches,cn=config objectClass: top objectClass: ds-cfg-entry-cache objectClass: ds-cfg-fifo-entry-cache cn: FIFO ds-cfg-enabled: false ds-cfg-cache-level: 2 ds-cfg-java-class: org.opends.server.extensions.FIFOEntryCache dn: cn=File System,cn=Entry Caches,cn=config objectClass: top objectClass: ds-cfg-entry-cache objectClass: ds-cfg-file-system-entry-cache cn: File System ds-cfg-enabled: false ds-cfg-cache-level: 3 ds-cfg-java-class: org.opends.server.extensions.FileSystemEntryCache dn: cn=Extended Operations,cn=config objectClass: top @@ -1171,11 +1195,11 @@ ds-cfg-java-class: org.opends.server.monitors.ClientConnectionMonitorProvider ds-cfg-enabled: true dn: cn=Entry Cache,cn=Monitor Providers,cn=config dn: cn=Entry Caches,cn=Monitor Providers,cn=config objectClass: top objectClass: ds-cfg-monitor-provider objectClass: ds-cfg-entry-cache-monitor-provider cn: Entry Cache cn: Entry Caches ds-cfg-java-class: org.opends.server.monitors.EntryCacheMonitorProvider ds-cfg-enabled: true opends/resource/schema/02-config.ldif
@@ -1543,6 +1543,11 @@ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.999 NAME 'ds-cfg-cache-level' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.315 NAME 'ds-cfg-allow-retrieving-membership' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 @@ -2328,7 +2333,8 @@ STRUCTURAL MUST ( cn $ ds-cfg-java-class $ ds-cfg-enabled ) ds-cfg-enabled $ ds-cfg-cache-level ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.15 NAME 'ds-cfg-fifo-entry-cache' opends/src/admin/defn/org/opends/server/admin/std/EntryCacheConfiguration.xml
@@ -80,4 +80,19 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="cache-level" mandatory="true"> <adm:synopsis> The entry cache level which specifies this cache position in the cache order if more than one instance of the cache is configured. </adm:synopsis> <adm:syntax> <adm:integer lower-limit="1" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:name>ds-cfg-cache-level</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/admin/defn/org/opends/server/admin/std/EntryCacheMonitorProviderConfiguration.xml
@@ -33,7 +33,7 @@ <adm:synopsis> The <adm:user-friendly-name /> exposes monitor information about Directory Server entry cache exposes monitor information about Directory Server entry caches state. </adm:synopsis> <adm:profile name="ldap"> opends/src/admin/defn/org/opends/server/admin/std/FileSystemEntryCacheConfiguration.xml
@@ -151,7 +151,7 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="cache-directory" mandatory="true"> <adm:property name="cache-directory"> <adm:synopsis> Specifies the directory in which the JE environment should store the cache. opends/src/admin/defn/org/opends/server/admin/std/RootConfiguration.xml
@@ -204,12 +204,13 @@ </adm:profile> </adm:relation> <adm:relation name="entry-cache"> <adm:one-to-zero-or-one /> <adm:one-to-many /> <adm:profile name="ldap"> <ldap:rdn-sequence>cn=Entry Cache,cn=config</ldap:rdn-sequence> <ldap:rdn-sequence>cn=Entry Caches,cn=config</ldap:rdn-sequence> </adm:profile> <adm:profile name="cli"> <cli:relation> <cli:default-property name="cache-level" /> <cli:default-property name="enabled" /> </cli:relation> </adm:profile> opends/src/messages/messages/config.properties
@@ -692,11 +692,10 @@ invalid value for configuration attribute ds-cfg-check-schema (it should be a \ Boolean value of true or false): %s SEVERE_ERR_CONFIG_ENTRYCACHE_CANNOT_INSTALL_DEFAULT_CACHE_200=An unexpected \ error occurred that prevented the server from installing a temporary default \ entry cache for use until the actual cache could be created from the \ configuration: %s error occurred that prevented the server from installing its default entry \ cache framework: %s SEVERE_WARN_CONFIG_ENTRYCACHE_NO_CONFIG_ENTRY_201=The entry cache \ configuration entry "cn=Entry Cache,cn=config" does not exist in the \ configuration entry "cn=Entry Caches,cn=config" does not exist in the \ Directory Server configuration. No entry cache will be available until this \ entry is created with a valid entry cache configuration SEVERE_ERR_CONFIG_ENTRYCACHE_CANNOT_INITIALIZE_CACHE_202=An error occurred \ @@ -705,6 +704,15 @@ disabled SEVERE_ERR_CONFIG_ENTRYCACHE_CONFIG_NOT_ACCEPTABLE_203=The configuration for \ the entry cache defined in configuration entry %s was not acceptable: %s SEVERE_ERR_CONFIG_ENTRYCACHE_CONFIG_LEVEL_NOT_ACCEPTABLE_204=The configuration \ for the entry cache defined in configuration entry %s was not acceptable: \ the entry cache level %d is already in use INFO_WARN_CONFIG_ENTRYCACHE_NO_MONITOR_CONFIG_ENTRY_205=The configuration for \ the entry cache %s monitor provider was not available. As a result this \ monitor provider %s will not be enabled INFO_WARN_CONFIG_ENTRYCACHE_MONITOR_CONFIG_DISABLED_206=The configuration for \ the entry cache %s monitor provider was disabled. As a result the monitor \ provider %s will not be enabled MILD_ERR_CONFIG_ENTRY_CANNOT_REMOVE_CHILD_215=An unexpected error occurred \ while attempting to remove entry %s as a child of configuration entry %s: %s SEVERE_WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM_216=Unable to parse a name \ opends/src/server/org/opends/server/api/EntryCache.java
@@ -30,10 +30,10 @@ import java.util.List; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; import org.opends.server.core.DirectoryServer; @@ -45,9 +45,10 @@ import org.opends.server.types.LockManager; import org.opends.server.types.SearchFilter; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.Attribute; import org.opends.server.admin.std.server.EntryCacheCfg; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.monitors.EntryCacheMonitorProvider; import org.opends.server.types.Attribute; import static org.opends.server.loggers.debug.DebugLogger.*; @@ -70,8 +71,8 @@ * mechanism to determine which entries to store, and entries * not matching the appropriate criteria may not be stored.</LI> * <LI>The entry cache may not actually store any entries (this is * the behavior of the default cache that will be used if none * is configured).</LI> * the behavior of the default cache if no implementation * specific entry cache is available).</LI> * </UL> * * @param <T> The type of configuration handled by this entry @@ -92,14 +93,12 @@ */ private static final DebugTracer TRACER = getTracer(); // The set of filters that define the entries that should be // The set of filters that define the entries that should be // excluded from the cache. private Set<SearchFilter> excludeFilters = new HashSet<SearchFilter>(0); // The set of filters that define the entries that should be // The set of filters that define the entries that should be // included in the cache. private Set<SearchFilter> includeFilters = new HashSet<SearchFilter>(0); @@ -118,6 +117,8 @@ */ protected AtomicLong cacheMisses = new AtomicLong(0); // The monitor associated with this entry cache. private EntryCacheMonitorProvider entryCacheMonitor = null; /** @@ -253,7 +254,7 @@ if (!containsEntry(entryDN)) { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); return null; } @@ -408,7 +409,7 @@ DN entryDN = getEntryDN(backend, entryID); if (entryDN == null) { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); return null; } @@ -450,7 +451,7 @@ * @return The entry DN for the requested entry, or * {@code null} if it is not present in the cache. */ protected abstract DN getEntryDN(Backend backend, long entryID); public abstract DN getEntryDN(Backend backend, long entryID); @@ -545,6 +546,33 @@ /** * Retrieves the monitor that is associated with this entry * cache. * * @return The monitor that is associated with this entry * cache, or {@code null} if none has been assigned. */ public final EntryCacheMonitorProvider getEntryCacheMonitor() { return entryCacheMonitor; } /** * Sets the monitor for this entry cache. * * @param entryCacheMonitor The monitor for this entry cache. */ public final void setEntryCacheMonitor( EntryCacheMonitorProvider entryCacheMonitor) { this.entryCacheMonitor = entryCacheMonitor; } /** * Retrieves a set of attributes containing monitor data that should * be returned to the client if the corresponding monitor entry is * requested. @@ -558,6 +586,39 @@ /** * Retrieves the curent number of entries stored within the cache. * * @return The current number of entries stored within the cache. */ public abstract Long getCacheCount(); /** * Retrieves the curent number of cache hits for this cache. * * @return The current number of cache hits for this cache. */ public Long getCacheHits() { return new Long(cacheHits.longValue()); } /** * Retrieves the curent number of cache misses for this cache. * * @return The current number of cache misses for this cache. */ public Long getCacheMisses() { return new Long(cacheMisses.longValue()); } /** * Retrieves the maximum length of time in milliseconds to wait for * a lock before giving up. * @@ -667,7 +728,7 @@ * @return {@code true} if current set of filters allow caching the * entry and {@code false} otherwise. */ protected boolean filtersAllowCaching(Entry entry) public boolean filtersAllowCaching(Entry entry) { // If there is a set of exclude filters, then make sure that the // provided entry doesn't match any of them. opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -2771,8 +2771,8 @@ * The DN of the entry that will hold the configuration for the Directory * Server entry cache. */ public static final String DN_ENTRY_CACHE_CONFIG = "cn=Entry Cache," + DN_CONFIG_ROOT; public static final String DN_ENTRY_CACHE_BASE = "cn=Entry Caches," + DN_CONFIG_ROOT; @@ -2982,6 +2982,15 @@ /** * The DN of the entry that will serve as the entry cache monitor provider * configuration for all Directory Server entry cache monitors. */ public static final String DN_ENTRY_CACHE_MONITOR_CONFIG = "cn=Entry Caches," + DN_MONITOR_CONFIG_BASE; /** * The DN of the entry that will serve as the base for all Directory Server * monitor information. */ 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) opends/src/server/org/opends/server/extensions/DefaultEntryCache.java
@@ -22,42 +22,59 @@ * CDDL HEADER END * * * Portions Copyright 2006-2007 Sun Microsystems, Inc. * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.extensions; import java.lang.reflect.Method; import org.opends.messages.Message; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.concurrent.locks.Lock; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.EntryCacheCfg; import org.opends.server.api.Backend; import org.opends.server.api.EntryCache; import org.opends.server.config.ConfigException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.Attribute; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.LockType; import org.opends.server.types.ResultCode; import static org.opends.server.loggers.debug.DebugLogger.*; /** * This class defines the default entry cache that will be used in the server if * none is configured. It does not actually store any entries, so all calls to * <CODE>getEntry</CODE> will return <CODE>null</CODE>, and all calls to * <CODE>putEntry</CODE> will return immediately without doing anything. * This class defines the default entry cache which acts as an arbiter for * every entry cache implemenation configured and installed withhin the * Directory Server or acts an an empty cache if no implementation specific * entry cache is configured. It does not actually store any entries, so * all calls to the entry cache public API are routed to underlying entry * cache according to the current configuration order and preferences. */ public class DefaultEntryCache extends EntryCache<EntryCacheCfg> implements ConfigurationChangeListener<EntryCacheCfg> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // The entry cache order array reflects all currently configured and // active entry cache implementations in cache level specific order. private static EntryCache<? extends EntryCacheCfg>[] cacheOrder = new EntryCache<?>[0]; /** * Creates a new instance of this default entry cache. @@ -65,11 +82,9 @@ public DefaultEntryCache() { super(); } /** * {@inheritDoc} */ @@ -80,7 +95,6 @@ } /** * {@inheritDoc} */ @@ -90,25 +104,98 @@ } /** * {@inheritDoc} */ public boolean containsEntry(DN entryDN) { // This implementation does not store any entries. if (entryDN == null) { return false; } for (EntryCache entryCache : cacheOrder) { if (entryCache.containsEntry(entryDN)) { return true; } } return false; } /** * {@inheritDoc} */ @Override public Entry getEntry(DN entryDN, LockType lockType, List<Lock> lockList) { Entry entry = null; for (EntryCache<? extends EntryCacheCfg> entryCache : cacheOrder) { entry = entryCache.getEntry(entryDN, lockType, lockList); if (entry != null) { break; } } // Indicate global cache miss. if ((entry == null) && (cacheOrder.length != 0)) { cacheMisses.getAndIncrement(); } return entry; } /** * {@inheritDoc} */ @Override public Entry getEntry(Backend backend, long entryID, LockType lockType, List<Lock> lockList) { Entry entry = null; for (EntryCache<? extends EntryCacheCfg> entryCache : cacheOrder) { entry = entryCache.getEntry(backend, entryID, lockType, lockList); if (entry != null) { break; } } // Indicate global cache miss. if ((entry == null) && (cacheOrder.length != 0)) { cacheMisses.getAndIncrement(); } return entry; } /** * {@inheritDoc} */ public Entry getEntry(DN entryDN) { // This implementation does not store any entries. return null; Entry entry = null; for (EntryCache entryCache : cacheOrder) { entry = entryCache.getEntry(entryDN); if (entry != null) { break; } } // Indicate global cache miss. if ((entry == null) && (cacheOrder.length != 0)) { cacheMisses.getAndIncrement(); } return entry; } @@ -118,8 +205,16 @@ */ public long getEntryID(DN entryDN) { // This implementation does not store any entries. return -1; long entryID = -1; for (EntryCache entryCache : cacheOrder) { entryID = entryCache.getEntryID(entryDN); if (entryID != -1) { break; } } return entryID; } @@ -127,10 +222,18 @@ /** * {@inheritDoc} */ protected DN getEntryDN(Backend backend, long entryID) public DN getEntryDN(Backend backend, long entryID) { // This implementation does not store any entries. return null; DN entryDN = null; for (EntryCache entryCache : cacheOrder) { entryDN = entryCache.getEntryDN(backend, entryID); if (entryDN != null) { break; } } return entryDN; } @@ -140,7 +243,14 @@ */ public void putEntry(Entry entry, Backend backend, long entryID) { // This implementation does not store entries. for (EntryCache entryCache : cacheOrder) { // The first cache in the order which can take this entry // gets it. if (entryCache.filtersAllowCaching(entry)) { entryCache.putEntry(entry, backend, entryID); break; } } } @@ -150,9 +260,15 @@ */ public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) { // This implementation does not store entries, so we will never have a // conflict. return true; for (EntryCache entryCache : cacheOrder) { // The first cache in the order which can take this entry // gets it. if (entryCache.filtersAllowCaching(entry)) { return entryCache.putEntryIfAbsent(entry, backend, entryID); } } return false; } @@ -162,7 +278,12 @@ */ public void removeEntry(DN entryDN) { // This implementation does not store entries. for (EntryCache entryCache : cacheOrder) { if (entryCache.containsEntry(entryDN)) { entryCache.removeEntry(entryDN); break; } } } @@ -172,7 +293,9 @@ */ public void clear() { // This implementation does not store entries. for (EntryCache entryCache : cacheOrder) { entryCache.clear(); } } @@ -182,7 +305,9 @@ */ public void clearBackend(Backend backend) { // This implementation does not store entries. for (EntryCache entryCache : cacheOrder) { entryCache.clearBackend(backend); } } @@ -192,7 +317,9 @@ */ public void clearSubtree(DN baseDN) { // This implementation does not store entries. for (EntryCache entryCache : cacheOrder) { entryCache.clearSubtree(baseDN); } } @@ -202,8 +329,9 @@ */ public void handleLowMemory() { // This implementation does not store entries, so there are no resources // that it can free. for (EntryCache entryCache : cacheOrder) { entryCache.handleLowMemory(); } } @@ -230,7 +358,6 @@ ) { // No implementation required. ConfigChangeResult changeResult = new ConfigChangeResult( ResultCode.SUCCESS, false, new ArrayList<Message>() ); @@ -245,9 +372,124 @@ */ public ArrayList<Attribute> getMonitorData() { // This implementation does not store entries, // so there is no monitoring data to provide. return new ArrayList<Attribute>(); ArrayList<Attribute> attrs = new ArrayList<Attribute>(); // The sum of cache hits of all active entry cache // implementations. Long entryCacheHits = new Long(0); // Common for all active entry cache implementations. Long entryCacheMisses = new Long(cacheMisses.longValue()); // The sum of cache counts of all active entry cache // implementations. Long currentEntryCacheCount = new Long(0); for (EntryCache entryCache : cacheOrder) { // Get cache hits and counts from every active cache. entryCacheHits += entryCache.getCacheHits(); currentEntryCacheCount += entryCache.getCacheCount(); } try { attrs = EntryCacheCommon.getGenericMonitorData( entryCacheHits, entryCacheMisses, null, null, currentEntryCacheCount, null ); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } return attrs; } /** * {@inheritDoc} */ public Long getCacheCount() { Long cacheCount = new Long(0); for (EntryCache entryCache : cacheOrder) { cacheCount += entryCache.getCacheCount(); } return cacheCount; } /** * Return a verbose string representation of the current cache maps. * This is useful primary for debugging and diagnostic purposes such * as in the entry cache unit tests. * @return String verbose string representation of the current cache * maps in the following format: dn:id:backend * one cache entry map representation per line * or <CODE>null</CODE> if all maps are empty. */ private String toVerboseString() { String verboseString = new String(); StringBuilder sb = new StringBuilder(); for (EntryCache entryCache : cacheOrder) { final Method[] cacheMethods = entryCache.getClass().getDeclaredMethods(); for (int i = 0; i < cacheMethods.length; ++i) { if (cacheMethods[i].getName().equals("toVerboseString")) { cacheMethods[i].setAccessible(true); try { Object cacheVerboseString = cacheMethods[i].invoke(entryCache, (Object[]) null); if (cacheVerboseString != null) { sb.append((String) cacheVerboseString); } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } } } verboseString = sb.toString(); return (verboseString.length() > 0 ? verboseString : null); } /** * Retrieves the current cache order array. * * @return The current cache order array. */ public final EntryCache<? extends EntryCacheCfg>[] getCacheOrder() { return this.cacheOrder; } /** * Sets the current cache order array. * * @param cacheOrderMap The current cache order array. */ public final void setCacheOrder( SortedMap<Integer, EntryCache<? extends EntryCacheCfg>> cacheOrderMap) { this.cacheOrder = cacheOrderMap.values().toArray(new EntryCache<?>[0]); } } opends/src/server/org/opends/server/extensions/EntryCacheCommon.java
@@ -381,7 +381,7 @@ { ArrayList<Attribute> attrs = new ArrayList<Attribute>(); if ((cacheHits != null) && (cacheMisses != null)) { if (cacheHits != null) { AttributeType hitsAttrType = DirectoryServer.getDefaultAttributeType("entryCacheHits"); LinkedHashSet<AttributeValue> hitsValues = @@ -390,29 +390,31 @@ cacheHits.toString())); attrs.add(new Attribute(hitsAttrType, "entryCacheHits", hitsValues)); // Cache misses is required to get cache tries and hit ratio. if (cacheMisses != null) { AttributeType triesAttrType = DirectoryServer.getDefaultAttributeType("entryCacheTries"); LinkedHashSet<AttributeValue> triesValues = new LinkedHashSet<AttributeValue>(); Long cacheTries = cacheHits + cacheMisses; triesValues.add(new AttributeValue(triesAttrType, cacheTries.toString())); attrs.add(new Attribute(triesAttrType, "entryCacheTries", triesValues)); AttributeType triesAttrType = DirectoryServer.getDefaultAttributeType("entryCacheTries"); LinkedHashSet<AttributeValue> triesValues = new LinkedHashSet<AttributeValue>(); Long cacheTries = cacheHits + cacheMisses; triesValues.add(new AttributeValue(triesAttrType, cacheTries.toString())); attrs.add(new Attribute(triesAttrType, "entryCacheTries", triesValues)); AttributeType hitRatioAttrType = DirectoryServer.getDefaultAttributeType("entryCacheHitRatio"); LinkedHashSet<AttributeValue> hitRatioValues = new LinkedHashSet<AttributeValue>(); Double hitRatioRaw = cacheTries > 0 ? cacheHits.doubleValue() / cacheTries.doubleValue() : cacheHits.doubleValue() / 1; Double hitRatio = hitRatioRaw * 100D; hitRatioValues.add(new AttributeValue(hitRatioAttrType, Long.toString(hitRatio.longValue()))); attrs.add(new Attribute(hitRatioAttrType, "entryCacheHitRatio", hitRatioValues)); AttributeType hitRatioAttrType = DirectoryServer.getDefaultAttributeType("entryCacheHitRatio"); LinkedHashSet<AttributeValue> hitRatioValues = new LinkedHashSet<AttributeValue>(); Double hitRatioRaw = cacheTries > 0 ? cacheHits.doubleValue() / cacheTries.doubleValue() : cacheHits.doubleValue() / 1; Double hitRatio = hitRatioRaw * 100D; hitRatioValues.add(new AttributeValue(hitRatioAttrType, Long.toString(hitRatio.longValue()))); attrs.add(new Attribute(hitRatioAttrType, "entryCacheHitRatio", hitRatioValues)); } } if (cacheSize != null) { opends/src/server/org/opends/server/extensions/FIFOEntryCache.java
@@ -213,6 +213,10 @@ */ public boolean containsEntry(DN entryDN) { if (entryDN == null) { return false; } // Indicate whether the DN map contains the specified DN. return dnMap.containsKey(entryDN); } @@ -229,13 +233,13 @@ if (e == null) { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); return null; } else { // Indicate cache hit. cacheHits.set(cacheHits.incrementAndGet()); cacheHits.getAndIncrement(); return e.getEntry(); } } @@ -264,7 +268,7 @@ /** * {@inheritDoc} */ protected DN getEntryDN(Backend backend, long entryID) public DN getEntryDN(Backend backend, long entryID) { // Locate specific backend map and return the entry DN by ID. HashMap<Long,CacheEntry> backendMap = idMap.get(backend); @@ -284,11 +288,6 @@ */ public void putEntry(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return; } // Create the cache entry based on the provided information. CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); @@ -400,11 +399,6 @@ */ public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return true; } // Create the cache entry based on the provided information. CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); @@ -1004,7 +998,9 @@ try { attrs = EntryCacheCommon.getGenericMonitorData( new Long(cacheHits.longValue()), new Long(cacheMisses.longValue()), // If cache misses is maintained by default cache // get it from there and if not point to itself. DirectoryServer.getEntryCache().getCacheMisses(), null, new Long(maxAllowedMemory), new Long(dnMap.size()), @@ -1024,6 +1020,16 @@ /** * {@inheritDoc} */ public Long getCacheCount() { return new Long(dnMap.size()); } /** * Return a verbose string representation of the current cache maps. * This is useful primary for debugging and diagnostic purposes such * as in the entry cache unit tests. opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
@@ -78,8 +78,8 @@ import org.opends.server.types.FilePermission; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.OpenDsException; import org.opends.server.types.Attribute; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.Attribute; import org.opends.server.util.ServerConstants; import static org.opends.server.loggers.debug.DebugLogger.*; @@ -607,6 +607,10 @@ */ public boolean containsEntry(DN entryDN) { if (entryDN == null) { return false; } // Indicate whether the DN map contains the specified DN. boolean containsEntry = false; cacheReadLock.lock(); @@ -631,10 +635,10 @@ if (dnMap.get(entryDN) != null) { entry = getEntryFromDB(entryDN); // Indicate cache hit. cacheHits.set(cacheHits.incrementAndGet()); cacheHits.getAndIncrement(); } else { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); } } finally { cacheReadLock.unlock(); @@ -662,7 +666,7 @@ /** * {@inheritDoc} */ protected DN getEntryDN(Backend backend, long entryID) { public DN getEntryDN(Backend backend, long entryID) { DN entryDN = null; cacheReadLock.lock(); @@ -684,13 +688,8 @@ /** * {@inheritDoc} */ public void putEntry(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return; } public void putEntry(Entry entry, Backend backend, long entryID) { // Obtain a lock on the cache. If this fails, then don't do anything. try { if (!cacheWriteLock.tryLock(getLockTimeout(), TimeUnit.MILLISECONDS)) { @@ -714,11 +713,6 @@ */ public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return true; } try { // Obtain a lock on the cache. If this fails, then don't do anything. if (! cacheWriteLock.tryLock(getLockTimeout(), TimeUnit.MILLISECONDS)) { @@ -1350,7 +1344,9 @@ try { attrs = EntryCacheCommon.getGenericMonitorData( new Long(cacheHits.longValue()), new Long(cacheMisses.longValue()), // If cache misses is maintained by default cache // get it from there and if not point to itself. DirectoryServer.getEntryCache().getCacheMisses(), new Long(entryCacheEnv.getStats( entryCacheEnvStatsConfig).getTotalLogSize()), new Long(maxAllowedMemory), @@ -1369,6 +1365,14 @@ } /** * {@inheritDoc} */ public Long getCacheCount() { return new Long(dnMap.size()); } /** * Retrieves and decodes the entry with the specified DN from JE backend db. * * @param entryDN The DN of the entry to retrieve. opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java
@@ -195,6 +195,10 @@ */ public boolean containsEntry(DN entryDN) { if (entryDN == null) { return false; } // Indicate whether the DN map contains the specified DN. return dnMap.containsKey(entryDN); } @@ -210,7 +214,7 @@ if (ref == null) { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); return null; } else @@ -219,13 +223,13 @@ if (cacheEntry == null) { // Indicate cache miss. cacheMisses.set(cacheMisses.incrementAndGet()); cacheMisses.getAndIncrement(); return null; } else { // Indicate cache hit. cacheHits.set(cacheHits.incrementAndGet()); cacheHits.getAndIncrement(); return cacheEntry.getEntry(); } } @@ -262,7 +266,7 @@ /** * {@inheritDoc} */ protected DN getEntryDN(Backend backend, long entryID) public DN getEntryDN(Backend backend, long entryID) { // Locate specific backend map and return the entry DN by ID. ConcurrentHashMap<Long,SoftReference<CacheEntry>> @@ -286,11 +290,6 @@ */ public void putEntry(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return; } // Create the cache entry based on the provided information. CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); SoftReference<CacheEntry> ref = @@ -327,11 +326,6 @@ public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) { // Check exclude and include filters first. if (!filtersAllowCaching(entry)) { return true; } // See if the entry already exists. If so, then return false. if (dnMap.containsKey(entry.getDN())) { @@ -667,7 +661,9 @@ try { attrs = EntryCacheCommon.getGenericMonitorData( new Long(cacheHits.longValue()), new Long(cacheMisses.longValue()), // If cache misses is maintained by default cache // get it from there and if not point to itself. DirectoryServer.getEntryCache().getCacheMisses(), null, null, new Long(dnMap.size()), @@ -685,6 +681,16 @@ /** * {@inheritDoc} */ public Long getCacheCount() { return new Long(dnMap.size()); } /** * Return a verbose string representation of the current cache maps. * This is useful primary for debugging and diagnostic purposes such * as in the entry cache unit tests. opends/src/server/org/opends/server/monitors/EntryCacheMonitorProvider.java
@@ -27,21 +27,20 @@ package org.opends.server.monitors; import java.util.ArrayList; import org.opends.messages.Message; import org.opends.server.admin.server.ServerManagementContext; import org.opends.server.admin.std.server.EntryCacheCfg; import org.opends.server.admin.std.server.EntryCacheMonitorProviderCfg; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.api.EntryCache; import org.opends.server.api.MonitorProvider; import org.opends.server.config.ConfigConstants; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.Attribute; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.InitializationException; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.loggers.ErrorLogger.*; import static org.opends.messages.ConfigMessages.*; /** * This class defines a Directory Server monitor provider that can be used to @@ -51,29 +50,73 @@ public class EntryCacheMonitorProvider extends MonitorProvider<EntryCacheMonitorProviderCfg> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // The name for this monitor. private String monitorName; // The entry cache common name. private String entryCacheName; // The entry cache with which this monitor is associated. private EntryCache<? extends EntryCacheCfg> entryCache; // Global entry cache monitor configuration. private static EntryCacheMonitorProviderCfg monitorConfiguration; /** * Creates an instance of this monitor provider. * Creates default instance of this monitor provider. */ public EntryCacheMonitorProvider() { super("Entry Cache Monitor Provider"); super("Entry Caches Monitor Provider"); this.entryCacheName = "Entry Caches"; this.entryCache = (EntryCache<? extends EntryCacheCfg>) DirectoryServer.getEntryCache(); } // No initialization should be performed here. /** * Creates implementation specific instance of this monitor provider. * * @param entryCacheName The name to use for this monitor provider. * @param entryCache The entry cache to associate this monitor * provider with. */ public EntryCacheMonitorProvider( String entryCacheName, EntryCache<? extends EntryCacheCfg> entryCache) { super(entryCacheName + " Entry Cache Monitor Provider"); this.entryCacheName = entryCacheName; this.entryCache = entryCache; } /** * {@inheritDoc} */ public void initializeMonitorProvider( EntryCacheMonitorProviderCfg configuration) throws ConfigException, InitializationException EntryCacheMonitorProviderCfg configuration) throws ConfigException { // No initialization is required. monitorName = entryCacheName; if (configuration != null) { monitorConfiguration = configuration; } if (monitorConfiguration == null) { Message message = INFO_WARN_CONFIG_ENTRYCACHE_NO_MONITOR_CONFIG_ENTRY.get( ConfigConstants.DN_ENTRY_CACHE_MONITOR_CONFIG, monitorName); logError(message); throw new ConfigException(message); } if (!monitorConfiguration.isEnabled()) { Message message = INFO_WARN_CONFIG_ENTRYCACHE_MONITOR_CONFIG_DISABLED.get( ConfigConstants.DN_ENTRY_CACHE_MONITOR_CONFIG, monitorName); logError(message); throw new ConfigException(message); } } /** @@ -81,7 +124,7 @@ */ public String getMonitorInstanceName() { return "Entry Cache"; return monitorName; } /** @@ -108,35 +151,12 @@ public ArrayList<Attribute> getMonitorData() { ArrayList<Attribute> attrs = new ArrayList<Attribute>(); EntryCacheCfg configuration = null; // Get the root configuration object. ServerManagementContext managementContext = ServerManagementContext.getInstance(); RootCfg rootConfiguration = managementContext.getRootConfiguration(); // Get the entry cache configuration. try { configuration = rootConfiguration.getEntryCache(); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } return attrs; } // Get the entry cache. EntryCache<? extends EntryCacheCfg> cache = (EntryCache<? extends EntryCacheCfg>) DirectoryServer.getEntryCache(); if ((cache != null) && (configuration != null) && configuration.isEnabled()) { // Get data from the cache. attrs = cache.getMonitorData(); if ((entryCache != null) && (monitorConfiguration != null) && (monitorConfiguration.isEnabled())) { // Get monitor data from the cache. attrs = entryCache.getMonitorData(); } return attrs; opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/DefaultEntryCacheTestCase.java
@@ -22,315 +22,507 @@ * CDDL HEADER END * * * Portions Copyright 2006-2007 Sun Microsystems, Inc. * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.server.extensions; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.SortedMap; import java.util.TreeMap; import org.opends.server.TestCaseUtils; import org.opends.server.admin.server.AdminTestCaseUtils; import org.testng.annotations.BeforeClass; import org.opends.server.admin.std.meta.*; import org.opends.server.admin.std.server.EntryCacheCfg; import org.opends.server.admin.std.server.FileSystemEntryCacheCfg; import org.opends.server.api.Backend; import org.opends.server.api.EntryCache; import org.opends.server.core.DirectoryServer; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.LockType; import org.opends.server.util.ServerConstants; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import static org.testng.Assert.*; /** * A set of test cases for the default entry cache. * A set of test cases for default entry cache implementation. */ @Test(groups = "entrycache", sequential=true) public class DefaultEntryCacheTestCase extends ExtensionsTestCase extends CommonEntryCacheTestCase { // Entry cache implementations participating in this test. private EntryCache softRefCache = null; private EntryCache fifoCache = null; private EntryCache fsCache = null; // ... and their configuration entries. Entry cacheSoftReferenceConfigEntry = null; Entry cacheFIFOConfigEntry = null; Entry cacheFSConfigEntry = null; // The entry cache order map sorted by the cache level. private SortedMap<Integer, EntryCache<? extends EntryCacheCfg>> cacheOrderMap = new TreeMap<Integer, EntryCache<? extends EntryCacheCfg>>(); // Dummy test entries for each participating implementation. private ArrayList<Entry> testSoftRefEntriesList = null; private ArrayList<Entry> testFIFOEntriesList = null; private ArrayList<Entry> testFSEntriesList = null; /** * Ensures that the Directory Server is running. * Initialize the entry cache test. * * @throws Exception If an unexpected problem occurs. */ @BeforeClass() public void startServer() @SuppressWarnings("unchecked") public void entryCacheTestInit() throws Exception { // Ensure that the server is running. TestCaseUtils.startServer(); // Get default cache. super.cache = DirectoryServer.getEntryCache(); // Configure and initialize all entry cache implementations. softRefCache = new SoftReferenceEntryCache(); cacheSoftReferenceConfigEntry = TestCaseUtils.makeEntry( "dn: cn=Soft Reference,cn=Entry Caches,cn=config", "objectClass: ds-cfg-soft-reference-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: Soft Reference", "ds-cfg-cache-level: 1", "ds-cfg-java-class: " + "org.opends.server.extensions.SoftReferenceEntryCache", "ds-cfg-enabled: true", "ds-cfg-include-filter: uid=softref*", "ds-cfg-include-filter: uid=test1*", "ds-cfg-exclude-filter: uid=test0*"); softRefCache.initializeEntryCache(AdminTestCaseUtils.getConfiguration( EntryCacheCfgDefn.getInstance(), cacheSoftReferenceConfigEntry)); cacheOrderMap.put(1, softRefCache); fifoCache = new FIFOEntryCache(); cacheFIFOConfigEntry = TestCaseUtils.makeEntry( "dn: cn=FIFO,cn=Entry Caches,cn=config", "objectClass: ds-cfg-fifo-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: FIFO", "ds-cfg-cache-level: 2", "ds-cfg-java-class: org.opends.server.extensions.FIFOEntryCache", "ds-cfg-enabled: true", "ds-cfg-include-filter: uid=fifo*", "ds-cfg-include-filter: uid=test2*", "ds-cfg-exclude-filter: uid=test0*"); fifoCache.initializeEntryCache(AdminTestCaseUtils.getConfiguration( EntryCacheCfgDefn.getInstance(), cacheFIFOConfigEntry)); cacheOrderMap.put(2, fifoCache); fsCache = new FileSystemEntryCache(); cacheFSConfigEntry = TestCaseUtils.makeEntry( "dn: cn=File System,cn=Entry Caches,cn=config", "objectClass: ds-cfg-file-system-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: File System", "ds-cfg-cache-level: 3", "ds-cfg-java-class: " + "org.opends.server.extensions.FileSystemEntryCache", "ds-cfg-enabled: true", "ds-cfg-include-filter: uid=fs*", "ds-cfg-include-filter: uid=test3*", "ds-cfg-include-filter: uid=test0*"); fsCache.initializeEntryCache(AdminTestCaseUtils.getConfiguration( EntryCacheCfgDefn.getInstance(), cacheFSConfigEntry)); cacheOrderMap.put(3, fsCache); // Plug all cache implementations into default entry cache. final Method[] defaultCacheMethods = super.cache.getClass().getDeclaredMethods(); for (int i = 0; i < defaultCacheMethods.length; ++i) { if (defaultCacheMethods[i].getName().equals("setCacheOrder")) { defaultCacheMethods[i].setAccessible(true); Object arglist[] = new Object[] { cacheOrderMap }; defaultCacheMethods[i].invoke(cache, arglist); } } // Make some dummy test entries. super.testEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES); for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { super.testEntriesList.add(TestCaseUtils.makeEntry( "dn: uid=test" + Integer.toString(i) + ".user" + Integer.toString(i) + ",ou=test" + Integer.toString(i) + ",o=test", "objectClass: person", "objectClass: inetorgperson", "objectClass: top", "objectClass: organizationalperson", "postalAddress: somewhere in Testville" + Integer.toString(i), "street: Under Construction Street" + Integer.toString(i), "l: Testcounty" + Integer.toString(i), "st: Teststate" + Integer.toString(i), "telephoneNumber: +878 8378 8378" + Integer.toString(i), "mobile: +878 8378 8378" + Integer.toString(i), "homePhone: +878 8378 8378" + Integer.toString(i), "pager: +878 8378 8378" + Integer.toString(i), "mail: test" + Integer.toString(i) + ".user" + Integer.toString(i) + "@testdomain.net", "postalCode: 8378" + Integer.toString(i), "userPassword: testpassword" + Integer.toString(i), "description: description for Test" + Integer.toString(i) + "User" + Integer.toString(i), "cn: Test" + Integer.toString(i) + "User" + Integer.toString(i), "sn: User" + Integer.toString(i), "givenName: Test" + Integer.toString(i), "initials: TST" + Integer.toString(i), "employeeNumber: 8378" + Integer.toString(i), "uid: test" + Integer.toString(i) + ".user" + Integer.toString(i)) ); } testSoftRefEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES); for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { testSoftRefEntriesList.add(TestCaseUtils.makeEntry( "dn: uid=softref" + Integer.toString(i) + ".user" + Integer.toString(i) + ",ou=test" + Integer.toString(i) + ",o=test", "objectClass: person", "objectClass: inetorgperson", "objectClass: top", "objectClass: organizationalperson", "uid: softref" + Integer.toString(i) + ".user" + Integer.toString(i)) ); } testFIFOEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES); for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { testFIFOEntriesList.add(TestCaseUtils.makeEntry( "dn: uid=fifo" + Integer.toString(i) + ".user" + Integer.toString(i) + ",ou=test" + Integer.toString(i) + ",o=test", "objectClass: person", "objectClass: inetorgperson", "objectClass: top", "objectClass: organizationalperson", "uid: fifo" + Integer.toString(i) + ".user" + Integer.toString(i)) ); } testFSEntriesList = new ArrayList<Entry>(super.NUMTESTENTRIES); for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { testFSEntriesList.add(TestCaseUtils.makeEntry( "dn: uid=fs" + Integer.toString(i) + ".user" + Integer.toString(i) + ",ou=test" + Integer.toString(i) + ",o=test", "objectClass: person", "objectClass: inetorgperson", "objectClass: top", "objectClass: organizationalperson", "uid: fs" + Integer.toString(i) + ".user" + Integer.toString(i)) ); } // Force GC to make sure we have enough memory for // the cache capping constraints to work properly. System.gc(); } /** * Tests the process of creating, initializing, and finalizing the cache. * Finalize the entry cache test. * * @throws Exception If an unexpected problem occurs. */ @Test() public void testInitializeAndFinalizeCache() @AfterClass() public void entryCacheTestFini() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.finalizeEntryCache(); // Finilize all entry cache implementations. for (EntryCache entryCache : cacheOrderMap.values()) { entryCache.finalizeEntryCache(); } // Remove default FS cache JE environment. FileSystemEntryCacheCfg config = (FileSystemEntryCacheCfg) AdminTestCaseUtils.getConfiguration(EntryCacheCfgDefn.getInstance(), cacheFSConfigEntry); TestCaseUtils.deleteDirectory(new File(config.getCacheDirectory())); } /** * Tests the <CODE>containsEntry</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testContainsEntry() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertFalse(cache.containsEntry(DN.decode("uid=test,o=test"))); cache.finalizeEntryCache(); super.testContainsEntry(); } /** * Tests the first <CODE>getEntry</CODE> method, which takes a single DN * argument. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testGetEntry1() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertNull(cache.getEntry(DN.decode("uid=test,o=test"))); cache.finalizeEntryCache(); super.testGetEntry1(); } /** * Tests the second <CODE>getEntry</CODE> method, which takes a DN, lock type, * and list attributes. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testGetEntry2() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertNull(cache.getEntry(DN.decode("uid=test,o=test"), LockType.NONE, new ArrayList<Lock>())); cache.finalizeEntryCache(); super.testGetEntry2(); } /** * Tests the third <CODE>getEntry</CODE> method, which takes a backend, entry * ID, lock type, and list attributes. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testGetEntry3() throws Exception { TestCaseUtils.initializeTestBackend(false); Backend b = DirectoryServer.getBackend(DN.decode("o=test")); DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertNull(cache.getEntry(b, -1, LockType.NONE, new ArrayList<Lock>())); cache.finalizeEntryCache(); super.testGetEntry3(); } /** * Tests the <CODE>getEntryID</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testGetEntryID() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertEquals(cache.getEntryID(DN.decode("uid=test,o=test")), -1); cache.finalizeEntryCache(); super.testGetEntryID(); } /** * Tests the <CODE>putEntry</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testPutEntry() throws Exception { TestCaseUtils.initializeTestBackend(false); Backend b = DirectoryServer.getBackend(DN.decode("o=test")); Entry e = TestCaseUtils.makeEntry("dn: o=test", "objectClass: top", "objectClass: organization", "o: test"); DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.putEntry(e, b, 1); cache.finalizeEntryCache(); super.testPutEntry(); } /** * Tests the <CODE>putEntryIfAbsent</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testPutEntryIfAbsent() throws Exception { TestCaseUtils.initializeTestBackend(false); Backend b = DirectoryServer.getBackend(DN.decode("o=test")); Entry e = TestCaseUtils.makeEntry("dn: o=test", "objectClass: top", "objectClass: organization", "o: test"); DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertTrue(cache.putEntryIfAbsent(e, b, 1)); cache.finalizeEntryCache(); super.testPutEntryIfAbsent(); } /** * Tests the <CODE>removeEntry</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testRemoveEntry() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.removeEntry(DN.decode("uid=test,o=test")); cache.finalizeEntryCache(); super.testRemoveEntry(); } /** * Tests the <CODE>clear</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testClear() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.clear(); cache.finalizeEntryCache(); super.testClear(); } /** * Tests the <CODE>clearBackend</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testClearBackend() throws Exception { TestCaseUtils.initializeTestBackend(false); Backend b = DirectoryServer.getBackend(DN.decode("o=test")); DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.clearBackend(b); cache.finalizeEntryCache(); super.testClearBackend(); } /** * Tests the <CODE>clearSubtree</CODE> method. * * @throws Exception If an unexpected problem occurs. * {@inheritDoc} */ @Test() @Override public void testClearSubtree() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); cache.clearSubtree(DN.decode("o=test")); cache.finalizeEntryCache(); super.testClearSubtree(); } /** * Tests the <CODE>handleLowMemory</CODE> method. * {@inheritDoc} */ @Test() @Override public void testHandleLowMemory() throws Exception { super.testHandleLowMemory(); } /** * Tests the entry cache level functionality where each set * of entries land on a specific cache level by some form * of selection criteria such as include / exclude filters. * * @throws Exception If an unexpected problem occurs. */ @Test() public void handleLowMemory() public void testCacheLevels() throws Exception { DefaultEntryCache cache = new DefaultEntryCache(); cache.initializeEntryCache(null); assertNull(toVerboseString(), "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL + toVerboseString()); cache.handleLowMemory(); TestCaseUtils.initializeTestBackend(false); Backend b = DirectoryServer.getBackend(DN.decode("o=test")); cache.finalizeEntryCache(); // Spread test entries among all cache levels via default cache. for (int i = 0; i < NUMTESTENTRIES; i++) { super.cache.putEntry(testSoftRefEntriesList.get(i), b, i); super.cache.putEntry(testFIFOEntriesList.get(i), b, i); super.cache.putEntry(testFSEntriesList.get(i), b, i); } // Ensure all test entries are available via default cache. for (int i = 0; i < NUMTESTENTRIES; i++) { assertNotNull(super.cache.getEntry( testSoftRefEntriesList.get(0).getDN()), "Expected to find " + testSoftRefEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); assertNotNull(super.cache.getEntry( testFIFOEntriesList.get(0).getDN()), "Expected to find " + testFIFOEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); assertNotNull(super.cache.getEntry( testFSEntriesList.get(0).getDN()), "Expected to find " + testFSEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); } // Ensure all test entries landed on their levels. for (int i = 0; i < NUMTESTENTRIES; i++) { assertNotNull(softRefCache.getEntry( testSoftRefEntriesList.get(0).getDN()), "Expected to find " + testSoftRefEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); assertNotNull(fifoCache.getEntry( testFIFOEntriesList.get(0).getDN()), "Expected to find " + testFIFOEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); assertNotNull(fsCache.getEntry( testFSEntriesList.get(0).getDN()), "Expected to find " + testFSEntriesList.get(0).getDN().toString() + " in the cache. Cache contents:" + ServerConstants.EOL + toVerboseString()); } // Clear the cache so that other tests can start from scratch. super.cache.clear(); } @BeforeGroups(groups = "testDefaultCacheConcurrency") public void cacheConcurrencySetup() throws Exception { assertNull(super.toVerboseString(), "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL + super.toVerboseString()); } @AfterGroups(groups = "testDefaultCacheConcurrency") public void cacheConcurrencyCleanup() throws Exception { // Clear the cache so that other tests can start from scratch. super.cache.clear(); } /** * {@inheritDoc} */ @Test(groups = { "slow", "testDefaultCacheConcurrency" }, threadPoolSize = 10, invocationCount = 10, timeOut = 60000) @Override public void testCacheConcurrency() throws Exception { super.testCacheConcurrency(); } } opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FIFOEntryCacheTestCase.java
@@ -68,11 +68,12 @@ // Configure this entry cache. Entry cacheConfigEntry = TestCaseUtils.makeEntry( "dn: cn=Entry Cache,cn=config", "dn: cn=FIFO,cn=Entry Caches,cn=config", "objectClass: ds-cfg-fifo-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: Entry Cache", "cn: FIFO", "ds-cfg-cache-level: 1", "ds-cfg-java-class: org.opends.server.extensions.FIFOEntryCache", "ds-cfg-enabled: true", "ds-cfg-max-entries: " + Integer.toString(super.MAXENTRIES)); opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/FileSystemEntryCacheTestCase.java
@@ -40,9 +40,7 @@ import org.opends.server.types.Attribute; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.OperatingSystem; import org.opends.server.util.ServerConstants; import org.opends.server.util.StaticUtils; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; @@ -200,11 +198,12 @@ // Configure this entry cache. cacheConfigEntry = TestCaseUtils.makeEntry( "dn: cn=Entry Cache,cn=config", "dn: cn=File System,cn=Entry Caches,cn=config", "objectClass: ds-cfg-file-system-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: Entry Cache", "cn: File System", "ds-cfg-cache-level: 1", "ds-cfg-java-class: " + "org.opends.server.extensions.FileSystemEntryCache", "ds-cfg-enabled: true", opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SoftReferenceEntryCacheTestCase.java
@@ -65,11 +65,12 @@ // Configure this entry cache. Entry cacheConfigEntry = TestCaseUtils.makeEntry( "dn: cn=Entry Cache,cn=config", "dn: cn=Soft Reference,cn=Entry Caches,cn=config", "objectClass: ds-cfg-soft-reference-entry-cache", "objectClass: ds-cfg-entry-cache", "objectClass: top", "cn: Entry Cache", "cn: Soft Reference", "ds-cfg-cache-level: 1", "ds-cfg-java-class: " + "org.opends.server.extensions.SoftReferenceEntryCache", "ds-cfg-enabled: true");