/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions copyright 2013 ForgeRock AS. */ package org.opends.server.api; import org.opends.messages.Message; import java.util.List; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.opends.server.config.ConfigException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.InitializationException; import org.opends.server.types.SearchFilter; import org.opends.server.types.DebugLogLevel; 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.*; /** * This class defines the set of methods that must be implemented by a * Directory Server entry cache. Note that components accessing the * entry cache must not depend on any particular behavior. For * example, if a call is made to {@code putEntry} to store an entry in * the cache, there is no guarantee that immediately calling * {@code getEntry} will be able to retrieve it. There are several * potential reasons for this, including: * <UL> * <LI>The entry may have been deleted or replaced by another thread * between the {@code putEntry} and {@code getEntry} calls.</LI> * <LI>The entry cache may implement a purging mechanism and the * entry added may have been purged between the * {@code putEntry} and {@code getEntry} calls.</LI> * <LI>The entry cache may implement some kind of filtering * 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 if no implementation * specific entry cache is available).</LI> * </UL> * * @param <T> The type of configuration handled by this entry * cache. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.VOLATILE, mayInstantiate=false, mayExtend=true, mayInvoke=true, notes="Entry cache methods may only be invoked by backends") public abstract class EntryCache <T extends EntryCacheCfg> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // 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 // included in the cache. private Set<SearchFilter> includeFilters = new HashSet<SearchFilter>(0); /** * Arbitrary number of cache hits for monitoring. */ protected AtomicLong cacheHits = new AtomicLong(0); /** * Arbitrary number of cache misses for monitoring. */ protected AtomicLong cacheMisses = new AtomicLong(0); // The monitor associated with this entry cache. private EntryCacheMonitorProvider entryCacheMonitor = null; /** * Default constructor which is implicitly called from all entry * cache implementations. */ public EntryCache() { // No implementation required. } /** * Initializes this entry cache implementation so that it will be * available for storing and retrieving entries. * * @param configuration The configuration to use to initialize * the entry cache. * * @throws ConfigException If there is a problem with the provided * configuration entry that would prevent * this entry cache from being used. * * @throws InitializationException If a problem occurs during the * initialization process that is * not related to the * configuration. */ public abstract void initializeEntryCache(T configuration) throws ConfigException, InitializationException; /** * Indicates whether the provided configuration is acceptable for * this entry cache. It should be possible to call this method on * an uninitialized entry cache instance in order to determine * whether the entry cache would be able to use the provided * configuration. * <BR><BR> * Note that implementations which use a subclass of the provided * configuration class will likely need to cast the configuration * to the appropriate subclass type. * * @param configuration The entry cache configuration for * which to make the determination. * @param unacceptableReasons A list that may be used to hold the * reasons that the provided * configuration is not acceptable. * * @return {@code true} if the provided configuration is acceptable * for this entry cache, or {@code false} if not. */ public boolean isConfigurationAcceptable( EntryCacheCfg configuration, List<Message> unacceptableReasons) { // This default implementation does not perform any special // validation. It should be overridden by entry cache // implementations that wish to perform more detailed validation. return true; } /** * Performs any necessary cleanup work (e.g., flushing all cached * entries and releasing any other held resources) that should be * performed when the server is to be shut down or the entry cache * destroyed or replaced. */ public abstract void finalizeEntryCache(); /** * Indicates whether the entry cache currently contains the entry * with the specified DN. This method may be called without holding * any locks if a point-in-time check is all that is required. * Note that this method is called from @see #getEntry(DN entryDN, * LockType lockType, List lockList) * * @param entryDN The DN for which to make the determination. * * @return {@code true} if the entry cache currently contains the * entry with the specified DN, or {@code false} if not. */ public abstract boolean containsEntry(DN entryDN); /** * Retrieves the entry with the specified DN from the cache. * * @param entryDN The DN of the entry to retrieve. * * @return The requested entry if it is present in the cache, or * {@code null} if it is not present. */ public abstract Entry getEntry(DN entryDN); /** * Retrieves the requested entry if it is present in the cache. * * @param backend The backend associated with the entry to * retrieve. * @param entryID The entry ID within the provided backend for * the specified entry. * * @return The requested entry if it is present in the cache, or * {@code null} if it is not present. */ public Entry getEntry(Backend backend, long entryID) { // Translate given backend/entryID pair to entryDN. DN entryDN = getEntryDN(backend, entryID); if (entryDN == null) { // Indicate cache miss. cacheMisses.getAndIncrement(); return null; } // Delegate to by DN lock and load method. return getEntry(entryDN); } /** * Retrieves the entry ID for the entry with the specified DN from * the cache. The caller should have already acquired a read or * write lock for the entry if such protection is needed. * * @param entryDN The DN of the entry for which to retrieve the * entry ID. * * @return The entry ID for the requested entry, or -1 if it is * not present in the cache. */ public abstract long getEntryID(DN entryDN); /** * Retrieves the entry DN for the entry with the specified ID on * the specific backend from the cache. The caller should have * already acquired a read or write lock for the entry if such * protection is needed. * Note that this method is called from @see #getEntry(Backend * backend, long entryID, LockType lockType, List lockList) * * @param backend The backend associated with the entry for * which to retrieve the entry DN. * @param entryID The entry ID within the provided backend * for which to retrieve the entry DN. * * @return The entry DN for the requested entry, or * {@code null} if it is not present in the cache. */ public abstract DN getEntryDN(Backend backend, long entryID); /** * Stores the provided entry in the cache. Note that the mechanism * that it uses to achieve this is implementation-dependent, and it * is acceptable for the entry to not actually be stored in any * cache. * * @param entry The entry to store in the cache. * @param backend The backend with which the entry is associated. * @param entryID The entry ID within the provided backend that * uniquely identifies the specified entry. */ public abstract void putEntry(Entry entry, Backend backend, long entryID); /** * Stores the provided entry in the cache only if it does not * conflict with an entry that already exists. Note that the * mechanism that it uses to achieve this is * implementation-dependent, and it is acceptable for the entry to * not actually be stored in any cache. However, this method must * not overwrite an existing version of the entry. * * @param entry The entry to store in the cache. * @param backend The backend with which the entry is associated. * @param entryID The entry ID within the provided backend that * uniquely identifies the specified entry. * * @return {@code false} if an existing entry or some other problem * prevented the method from completing successfully, or * {@code true} if there was no conflict and the entry was * either stored or the cache determined that this entry * should never be cached for some reason. */ public abstract boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID); /** * Removes the specified entry from the cache. * * @param entryDN The DN of the entry to remove from the cache. */ public abstract void removeEntry(DN entryDN); /** * Removes all entries from the cache. The cache should still be * available for future use. */ public abstract void clear(); /** * Removes all entries from the cache that are associated with the * provided backend. * * @param backend The backend for which to flush the associated * entries. */ public abstract void clearBackend(Backend backend); /** * Removes all entries from the cache that are below the provided * DN. * * @param baseDN The base DN below which all entries should be * flushed. */ public abstract void clearSubtree(DN baseDN); /** * Attempts to react to a scenario in which it is determined that * the system is running low on available memory. In this case, the * entry cache should attempt to free some memory if possible to try * to avoid out of memory errors. */ public abstract void handleLowMemory(); /** * 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. * * @return A set of attributes containing monitor data that should * be returned to the client if the corresponding monitor * entry is requested. */ public abstract ArrayList<Attribute> getMonitorData(); /** * Retrieves the current number of entries stored within the cache. * * @return The current number of entries stored within the cache. */ public abstract Long getCacheCount(); /** * Retrieves the current 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 current 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 set of search filters that may be used to determine * whether an entry should be excluded from the cache. * * @return The set of search filters that may be used to determine * whether an entry should be excluded from the cache. */ public Set<SearchFilter> getExcludeFilters() { return excludeFilters; } /** * Specifies the set of search filters that may be used to determine * whether an entry should be excluded from the cache. * * @param excludeFilters The set of search filters that may be * used to determine whether an entry should * be excluded from the cache. */ public void setExcludeFilters(Set<SearchFilter> excludeFilters) { if (excludeFilters == null) { this.excludeFilters = new HashSet<SearchFilter>(0); } else { this.excludeFilters = excludeFilters; } } /** * Retrieves the set of search filters that may be used to determine * whether an entry should be included in the cache. * * @return The set of search filters that may be used to determine * whether an entry should be included in the cache. */ public Set<SearchFilter> getIncludeFilters() { return includeFilters; } /** * Specifies the set of search filters that may be used to determine * whether an entry should be included in the cache. * * @param includeFilters The set of search filters that may be * used to determine whether an entry should * be included in the cache. */ public void setIncludeFilters(Set<SearchFilter> includeFilters) { if (includeFilters == null) { this.includeFilters = new HashSet<SearchFilter>(0); } else { this.includeFilters = includeFilters; } } /** * Indicates whether the current set of exclude and include filters * allow caching of the specified entry. * * @param entry The entry to evaluate against exclude and include * filter sets. * * @return {@code true} if current set of filters allow caching the * entry and {@code false} otherwise. */ 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. if (! excludeFilters.isEmpty()) { for (SearchFilter f : excludeFilters) { try { if (f.matchesEntry(entry)) { return false; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // This shouldn't happen, but if it does then we can't be // sure whether the entry should be excluded, so we will // by default. return false; } } } // If there is a set of include filters, then make sure that the // provided entry matches at least one of them. if (! includeFilters.isEmpty()) { boolean matchFound = false; for (SearchFilter f : includeFilters) { try { if (f.matchesEntry(entry)) { matchFound = true; break; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // This shouldn't happen, but if it does, then // just ignore it. } } if (! matchFound) { return false; } } return true; } /** * 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. * <p> * This method is invoked by unit tests for debugging. * * @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. */ public abstract String toVerboseString(); }