mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
19.29.2006 025d8fe096c5f981059c8c3cab6efb279ffdfe5f
Update the FIFO and soft reference entry cache implementations to convert the
lock timeout attribute to use an integer with unit syntax rather than just an
integer.

Also, update the FIFO entry cache implementation to get rid of the calls to run
the garbage collector. Instead, if we detect that too much memory is being
used, we'll not store the new entry and get rid of an old entry. This is much
more palatable in terms of performance and response time when the cache gets
full.
3 files modified
351 ■■■■ changed files
opends/resource/schema/02-config.ldif 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java 280 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java 69 ●●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif
@@ -205,7 +205,7 @@
  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.58
  NAME 'ds-cfg-lock-timeout' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
  NAME 'ds-cfg-lock-timeout' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.59 NAME 'ds-cfg-log-file'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java
@@ -47,6 +47,7 @@
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.IntegerConfigAttribute;
import org.opends.server.config.IntegerWithUnitConfigAttribute;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.InitializationException;
@@ -107,6 +108,15 @@
  /**
   * The set of time units that will be used for expressing the task retention
   * time.
   */
  private static final LinkedHashMap<String,Double> timeUnits =
       new LinkedHashMap<String,Double>();
  // The DN of the configuration entry for this entry cache.
  private DN configEntryDN;
@@ -147,6 +157,14 @@
  static
  {
    timeUnits.put("ms", 1.0);
    timeUnits.put("s", 1000.0);
  }
  /**
   * Creates a new instance of this FIFO entry cache.
   */
@@ -263,14 +281,14 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    lockTimeout = DEFAULT_FIFOCACHE_LOCK_TIMEOUT;
    msgID = MSGID_FIFOCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
      if (lockTimeoutAttr == null)
      {
@@ -278,7 +296,7 @@
      }
      else
      {
        lockTimeout = lockTimeoutAttr.activeValue();
        lockTimeout = lockTimeoutAttr.activeCalculatedValue();
      }
    }
    catch (Exception e)
@@ -442,9 +460,6 @@
    {
      idMap.clear();
      dnMap.clear();
      // FIXME -- Should we do this?
      runtime.gc();
    }
    catch (Exception e)
    {
@@ -873,71 +888,66 @@
    // lock before leaving this method, so do that in a finally block.
    try
    {
      // Add the entry to the cache.  This will replace it if it is already
      // present and add it if it isn't.
      dnMap.put(entry.getDN(), cacheEntry);
      HashMap<Long,CacheEntry> map = idMap.get(backend);
      if (map == null)
      // See if the current memory usage is within acceptable constraints.  If
      // so, then add the entry to the cache (or replace it if it is already
      // present).  If not, then remove an existing entry and don't add the new
      // entry.
      long usedMemory = runtime.totalMemory() - runtime.freeMemory();
      if (usedMemory > maxAllowedMemory)
      {
        map = new HashMap<Long,CacheEntry>();
        map.put(entryID, cacheEntry);
        idMap.put(backend, map);
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        if (iterator.hasNext())
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
          {
            m.remove(ce.getEntryID());
          }
        }
      }
      else
      {
        map.put(entryID, cacheEntry);
      }
        // Add the entry to the cache.  This will replace it if it is already
        // present and add it if it isn't.
        dnMap.put(entry.getDN(), cacheEntry);
      // See if a cap has been placed on the maximum number of entries in the
      // cache.  If so, then see if we have exceeded it and we need to purge
      // entries until we're within the limit.
      int entryCount = dnMap.size();
      if ((maxEntries > 0) && (entryCount > maxEntries))
      {
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        while (iterator.hasNext() && (entryCount > maxEntries))
        HashMap<Long,CacheEntry> map = idMap.get(backend);
        if (map == null)
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
          {
            m.remove(ce.getEntryID());
          }
          entryCount--;
          map = new HashMap<Long,CacheEntry>();
          map.put(entryID, cacheEntry);
          idMap.put(backend, map);
        }
      }
      // See if we need to free memory to bring the usage limits in line.
      long usedMemory = runtime.totalMemory() - runtime.freeMemory();
      while (usedMemory > maxAllowedMemory)
      {
        // Dump 1% of the entries and check again.
        int numEntries = entryCount / 100;
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        while (iterator.hasNext() && (numEntries > 0))
        else
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
          {
            m.remove(ce.getEntryID());
          }
          numEntries--;
          map.put(entryID, cacheEntry);
        }
        // FIXME -- Is there a better way to free the memory?
        runtime.gc();
        usedMemory = runtime.totalMemory() - runtime.freeMemory();
        // See if a cap has been placed on the maximum number of entries in the
        // cache.  If so, then see if we have exceeded it and we need to purge
        // entries until we're within the limit.
        int entryCount = dnMap.size();
        if ((maxEntries > 0) && (entryCount > maxEntries))
        {
          Iterator<CacheEntry> iterator = dnMap.values().iterator();
          while (iterator.hasNext() && (entryCount > maxEntries))
          {
            CacheEntry ce = iterator.next();
            iterator.remove();
            HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
            if (m != null)
            {
              m.remove(ce.getEntryID());
            }
            entryCount--;
          }
        }
      }
    }
    catch (Exception e)
@@ -1066,74 +1076,71 @@
        return false;
      }
      // Add the entry to the cache.  This will replace it if it is already
      // present and add it if it isn't.
      dnMap.put(entry.getDN(), cacheEntry);
      HashMap<Long,CacheEntry> map = idMap.get(backend);
      if (map == null)
      // See if the current memory usage is within acceptable constraints.  If
      // so, then add the entry to the cache (or replace it if it is already
      // present).  If not, then remove an existing entry and don't add the new
      // entry.
      long usedMemory = runtime.totalMemory() - runtime.freeMemory();
      if (usedMemory > maxAllowedMemory)
      {
        map = new HashMap<Long,CacheEntry>();
        map.put(entryID, cacheEntry);
        idMap.put(backend, map);
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        if (iterator.hasNext())
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
          {
            m.remove(ce.getEntryID());
          }
        }
      }
      else
      {
        map.put(entryID, cacheEntry);
      }
        // Add the entry to the cache.  This will replace it if it is already
        // present and add it if it isn't.
        dnMap.put(entry.getDN(), cacheEntry);
      // See if a cap has been placed on the maximum number of entries in the
      // cache.  If so, then see if we have exceeded it and we need to purge
      // entries until we're within the limit.
      int entryCount = dnMap.size();
      if ((maxEntries > 0) && (entryCount > maxEntries))
      {
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        while (iterator.hasNext() && (entryCount > maxEntries))
        HashMap<Long,CacheEntry> map = idMap.get(backend);
        if (map == null)
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          map = new HashMap<Long,CacheEntry>();
          map.put(entryID, cacheEntry);
          idMap.put(backend, map);
        }
        else
        {
          map.put(entryID, cacheEntry);
        }
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
        // See if a cap has been placed on the maximum number of entries in the
        // cache.  If so, then see if we have exceeded it and we need to purge
        // entries until we're within the limit.
        int entryCount = dnMap.size();
        if ((maxEntries > 0) && (entryCount > maxEntries))
        {
          Iterator<CacheEntry> iterator = dnMap.values().iterator();
          while (iterator.hasNext() && (entryCount > maxEntries))
          {
            m.remove(ce.getEntryID());
          }
            CacheEntry ce = iterator.next();
            iterator.remove();
          entryCount--;
            HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
            if (m != null)
            {
              m.remove(ce.getEntryID());
            }
            entryCount--;
          }
        }
      }
      // See if we need to free memory to bring the usage limits in line.
      long usedMemory = runtime.totalMemory() - runtime.freeMemory();
      while (usedMemory > maxAllowedMemory)
      {
        // Dump 1% of the entries and check again.
        int numEntries = entryCount / 100;
        Iterator<CacheEntry> iterator = dnMap.values().iterator();
        while (iterator.hasNext() && (numEntries > 0))
        {
          CacheEntry ce = iterator.next();
          iterator.remove();
          HashMap<Long,CacheEntry> m = idMap.get(ce.getBackend());
          if (m != null)
          {
            m.remove(ce.getEntryID());
          }
          numEntries--;
        }
        // FIXME -- Is there a better way to free the memory?
        runtime.gc();
        usedMemory = runtime.totalMemory() - runtime.freeMemory();
      }
      // We'll always return true in this case, even if we didn't actually add
      // the entry due to memory constraints.
      return true;
    }
    catch (Exception e)
@@ -1533,10 +1540,11 @@
    msgID = MSGID_FIFOCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutAttr =
         new IntegerConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0, lockTimeout);
    IntegerWithUnitConfigAttribute lockTimeoutAttr =
         new IntegerWithUnitConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0, lockTimeout,
                                            "ms");
    attrList.add(lockTimeoutAttr);
@@ -1649,14 +1657,14 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    msgID = MSGID_FIFOCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
    }
    catch (Exception e)
@@ -1890,18 +1898,18 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    long newLockTimeout = DEFAULT_FIFOCACHE_LOCK_TIMEOUT;
    msgID = MSGID_FIFOCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_FIFOCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
      if (lockTimeoutAttr != null)
      {
        newLockTimeout = lockTimeoutAttr.pendingValue();
        newLockTimeout = lockTimeoutAttr.pendingCalculatedValue();
      }
    }
    catch (Exception e)
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java
@@ -32,6 +32,7 @@
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@@ -43,7 +44,7 @@
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.config.ConfigException;
import org.opends.server.config.IntegerConfigAttribute;
import org.opends.server.config.IntegerWithUnitConfigAttribute;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.InitializationException;
@@ -84,6 +85,15 @@
  /**
   * The set of time units that will be used for expressing the task retention
   * time.
   */
  private static final LinkedHashMap<String,Double> timeUnits =
       new LinkedHashMap<String,Double>();
  // The mapping between entry DNs and their corresponding entries.
  private ConcurrentHashMap<DN,SoftReference<CacheEntry>> dnMap;
@@ -112,6 +122,14 @@
  static
  {
    timeUnits.put("ms", 1.0);
    timeUnits.put("s", 1000.0);
  }
  /**
   * Creates a new instance of this soft reference entry cache.  All
   * initialization should be performed in the <CODE>initializeEntryCache</CODE>
@@ -170,14 +188,14 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    int msgID = MSGID_SOFTREFCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
      if (lockTimeoutAttr == null)
      {
@@ -185,7 +203,7 @@
      }
      else
      {
        lockTimeout = lockTimeoutAttr.activeValue();
        lockTimeout = lockTimeoutAttr.activeCalculatedValue();
      }
    }
    catch (Exception e)
@@ -1054,10 +1072,11 @@
    int msgID = MSGID_SOFTREFCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutAttr =
         new IntegerConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0, lockTimeout);
    IntegerWithUnitConfigAttribute lockTimeoutAttr =
         new IntegerWithUnitConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0, lockTimeout,
                                            "ms");
    attrList.add(lockTimeoutAttr);
@@ -1121,14 +1140,14 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    int msgID = MSGID_SOFTREFCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
    }
    catch (Exception e)
@@ -1296,18 +1315,18 @@
    // Determine the lock timeout to use when interacting with the lock manager.
    long newLockTimeout = LockManager.DEFAULT_TIMEOUT;
    int msgID = MSGID_SOFTREFCACHE_DESCRIPTION_LOCK_TIMEOUT;
    IntegerConfigAttribute lockTimeoutStub =
         new IntegerConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                    getMessage(msgID), true, false, false,
                                    true, 0, false, 0);
    IntegerWithUnitConfigAttribute lockTimeoutStub =
         new IntegerWithUnitConfigAttribute(ATTR_SOFTREFCACHE_LOCK_TIMEOUT,
                                            getMessage(msgID), false, timeUnits,
                                            true, 0, false, 0);
    try
    {
      IntegerConfigAttribute lockTimeoutAttr =
             (IntegerConfigAttribute)
      IntegerWithUnitConfigAttribute lockTimeoutAttr =
             (IntegerWithUnitConfigAttribute)
             configEntry.getConfigAttribute(lockTimeoutStub);
      if (lockTimeoutAttr != null)
      {
        newLockTimeout = lockTimeoutAttr.pendingValue();
        newLockTimeout = lockTimeoutAttr.pendingCalculatedValue();
      }
    }
    catch (Exception e)