| | |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2014 ForgeRock AS |
| | | * Portions Copyright 2011-2015 ForgeRock AS |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | import static org.opends.messages.ExtensionMessages.*; |
| | | |
| | | import java.lang.ref.ReferenceQueue; |
| | | import java.lang.ref.SoftReference; |
| | | import java.util.ArrayList; |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.util.Utils; |
| | | 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.DirectoryThread; |
| | | import org.opends.server.api.EntryCache; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.CacheEntry; |
| | |
| | | import org.opends.server.types.SearchFilter; |
| | | import org.opends.server.util.ServerConstants; |
| | | |
| | | import static org.opends.messages.ExtensionMessages.*; |
| | | |
| | | /** |
| | | * This class defines a Directory Server entry cache that uses soft references |
| | | * to manage objects in a way that will allow them to be freed if the JVM is |
| | |
| | | { |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | // The mapping between entry DNs and their corresponding entries. |
| | | /** The mapping between entry DNs and their corresponding entries. */ |
| | | private ConcurrentHashMap<DN,SoftReference<CacheEntry>> dnMap; |
| | | |
| | | // The mapping between backend+ID and their corresponding entries. |
| | | /** The mapping between backend+ID and their corresponding entries. */ |
| | | private ConcurrentHashMap<Backend, |
| | | ConcurrentHashMap<Long,SoftReference<CacheEntry>>> idMap; |
| | | |
| | | // The reference queue that will be used to notify us whenever a soft |
| | | // reference is freed. |
| | | /** |
| | | * The reference queue that will be used to notify us whenever a soft |
| | | * reference is freed. |
| | | */ |
| | | private ReferenceQueue<CacheEntry> referenceQueue; |
| | | |
| | | // Currently registered configuration object. |
| | | /** Currently registered configuration object. */ |
| | | private SoftReferenceEntryCacheCfg registeredConfiguration; |
| | | |
| | | private Thread cleanerThread; |
| | | |
| | | private volatile boolean shutdown = false; |
| | | private volatile boolean shutdown; |
| | | |
| | | |
| | | |
| | |
| | | referenceQueue = new ReferenceQueue<CacheEntry>(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void initializeEntryCache( |
| | | SoftReferenceEntryCacheCfg configuration |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public synchronized void finalizeEntryCache() |
| | | { |
| | |
| | | dnMap.clear(); |
| | | idMap.clear(); |
| | | if (cleanerThread != null) { |
| | | for (int i = 0; cleanerThread.isAlive() && (i < 5); i++) { |
| | | for (int i = 0; cleanerThread.isAlive() && i < 5; i++) { |
| | | cleanerThread.interrupt(); |
| | | try { |
| | | cleanerThread.join(10); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean containsEntry(DN entryDN) |
| | | { |
| | | if (entryDN == null) { |
| | | return false; |
| | | } |
| | | |
| | | // Indicate whether the DN map contains the specified DN. |
| | | return dnMap.containsKey(entryDN); |
| | | return entryDN != null && dnMap.containsKey(entryDN); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Entry getEntry(DN entryDN) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public long getEntryID(DN entryDN) |
| | | { |
| | | SoftReference<CacheEntry> ref = dnMap.get(entryDN); |
| | | if (ref == null) |
| | | { |
| | | return -1; |
| | | } |
| | | else |
| | | if (ref != null) |
| | | { |
| | | CacheEntry cacheEntry = ref.get(); |
| | | if (cacheEntry == null) |
| | | { |
| | | return -1; |
| | | } |
| | | else |
| | | { |
| | | return cacheEntry.getEntryID(); |
| | | } |
| | | return cacheEntry != null ? cacheEntry.getEntryID() : -1; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getEntryDN(Backend backend, long entryID) |
| | | { |
| | |
| | | return null; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void putEntry(Entry entry, Backend backend, long entryID) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean putEntryIfAbsent(Entry entry, Backend backend, |
| | | long entryID) |
| | |
| | | return true; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void removeEntry(DN entryDN) |
| | | { |
| | |
| | | CacheEntry cacheEntry = ref.get(); |
| | | if (cacheEntry != null) |
| | | { |
| | | Backend backend = cacheEntry.getBackend(); |
| | | Backend<?> backend = cacheEntry.getBackend(); |
| | | |
| | | ConcurrentHashMap<Long,SoftReference<CacheEntry>> map = |
| | | idMap.get(backend); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clear() |
| | | { |
| | |
| | | idMap.clear(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clearBackend(Backend backend) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clearSubtree(DN baseDN) |
| | | { |
| | | // Determine the backend used to hold the specified base DN and clear it. |
| | | Backend backend = DirectoryServer.getBackend(baseDN); |
| | | Backend<?> backend = DirectoryServer.getBackend(baseDN); |
| | | if (backend == null) |
| | | { |
| | | // FIXME -- Should we clear everything just to be safe? |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void handleLowMemory() |
| | | { |
| | |
| | | // FIXME -- Do we need to do anything at all here? |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationAcceptable(EntryCacheCfg configuration, |
| | | List<LocalizableMessage> unacceptableReasons) |
| | | { |
| | |
| | | return isConfigurationChangeAcceptable(config, unacceptableReasons); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isConfigurationChangeAcceptable( |
| | | SoftReferenceEntryCacheCfg configuration, |
| | |
| | | return errorHandler.getIsAcceptable(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ConfigChangeResult applyConfigurationChange( |
| | | SoftReferenceEntryCacheCfg configuration |
| | | ) |
| | | public ConfigChangeResult applyConfigurationChange(SoftReferenceEntryCacheCfg configuration) |
| | | { |
| | | boolean applyChanges = true; |
| | | ArrayList<LocalizableMessage> errorMessages = new ArrayList<LocalizableMessage>(); |
| | |
| | | processEntryCacheConfig (configuration, applyChanges, errorHandler); |
| | | } |
| | | |
| | | boolean adminActionRequired = errorHandler.getIsAdminActionRequired(); |
| | | ConfigChangeResult changeResult = new ConfigChangeResult( |
| | | errorHandler.getResultCode(), |
| | | adminActionRequired, |
| | | errorHandler.getErrorMessages() |
| | | ); |
| | | final ConfigChangeResult changeResult = new ConfigChangeResult(); |
| | | changeResult.setResultCode(errorHandler.getResultCode()); |
| | | changeResult.setAdminActionRequired(errorHandler.getIsAdminActionRequired()); |
| | | changeResult.getMessages().addAll(errorHandler.getErrorMessages()); |
| | | return changeResult; |
| | | } |
| | | |
| | |
| | | return errorHandler.getIsAcceptable(); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Operate in a loop, receiving notification of soft references that have been |
| | | * freed and removing the corresponding entries from the cache. |
| | |
| | | { |
| | | ref.clear(); |
| | | |
| | | Backend backend = freedEntry.getBackend(); |
| | | Backend<?> backend = freedEntry.getBackend(); |
| | | ConcurrentHashMap<Long,SoftReference<CacheEntry>> map = |
| | | idMap.get(backend); |
| | | if (map != null) |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ArrayList<Attribute> getMonitorData() |
| | | { |
| | |
| | | |
| | | try { |
| | | attrs = EntryCacheCommon.getGenericMonitorData( |
| | | new Long(cacheHits.longValue()), |
| | | Long.valueOf(cacheHits.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()), |
| | | Long.valueOf(dnMap.size()), |
| | | null |
| | | ); |
| | | } catch (Exception e) { |
| | |
| | | return attrs; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Long getCacheCount() |
| | | { |
| | | return new Long(dnMap.size()); |
| | | return Long.valueOf(dnMap.size()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String toVerboseString() |
| | | { |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | // There're no locks in this cache to keep dnMap and idMap in |
| | | // sync. Examine dnMap only since its more likely to be up to |
| | | // date than idMap. Dont bother with copies either since this |
| | | // There're no locks in this cache to keep dnMap and idMap in sync. |
| | | // Examine dnMap only since its more likely to be up to date than idMap. |
| | | // Do not bother with copies either since this |
| | | // is SoftReference based implementation. |
| | | for(SoftReference<CacheEntry> ce : dnMap.values()) { |
| | | sb.append(ce.get().getDN()); |
| | |
| | | } |
| | | |
| | | String verboseString = sb.toString(); |
| | | |
| | | return (verboseString.length() > 0 ? verboseString : null); |
| | | return verboseString.length() > 0 ? verboseString : null; |
| | | } |
| | | } |
| | | |