From 4a58a441a5b81031a86bc01b630b9e19894f4d80 Mon Sep 17 00:00:00 2001
From: abobrov <abobrov@localhost>
Date: Sun, 02 Dec 2007 17:54:15 +0000
Subject: [PATCH] - [Issue 2007] generic mechanism for using mulitple caches. - [Issue 2049] dsconfig is unable to configure the entry cache.
---
opendj-sdk/opends/src/server/org/opends/server/extensions/DefaultEntryCache.java | 306 +++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 274 insertions(+), 32 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/DefaultEntryCache.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/DefaultEntryCache.java
index 4ba492d..c7912cf 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/DefaultEntryCache.java
+++ b/opendj-sdk/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]);
}
}
--
Gitblit v1.10.0