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

abobrov
20.28.2007 0ce8111bcd7c23226fa1fe7469baae9b1840eae4
- implement new toVerboseString() method.
- fix bugs found by entry cache unit tests.
- sanitize backend map maintenance.
5 files modified
184 ■■■■■ changed files
opends/src/server/org/opends/server/api/EntryCache.java 13 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/DefaultEntryCache.java 11 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java 62 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java 61 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java 37 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/EntryCache.java
@@ -526,6 +526,19 @@
  /**
   * 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.
   */
  public abstract String toVerboseString();
  /**
   * Retrieves the maximum length of time in milliseconds to wait for
   * a lock before giving up.
   *
opends/src/server/org/opends/server/extensions/DefaultEntryCache.java
@@ -210,6 +210,17 @@
  /**
   * {@inheritDoc}
   */
  public String toVerboseString()
  {
    // This implementation does not store entries.
    return null;
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(
      EntryCacheCfg configuration,
      List<Message> unacceptableReasons
opends/src/server/org/opends/server/extensions/FIFOEntryCache.java
@@ -562,9 +562,10 @@
        return;
      }
      Backend backend = entry.getBackend();
      // Try to remove the entry from the ID list as well.
      Map<Long,CacheEntry> map = idMap.get(entry.getBackend());
      Map<Long,CacheEntry> map = idMap.get(backend);
      if (map == null)
      {
        // This should't happen, but the entry isn't cached in the ID map so
@@ -573,6 +574,12 @@
      }
      map.remove(entry.getEntryID());
      // If this backend becomes empty now remove it from the idMap map.
      if (map.isEmpty())
      {
        idMap.remove(backend);
      }
    }
    catch (Exception e)
    {
@@ -858,6 +865,59 @@
  /**
   * {@inheritDoc}
   */
  public String toVerboseString()
  {
    String verboseString = new String();
    Map<DN,CacheEntry> dnMapCopy;
    Map<Backend,HashMap<Long,CacheEntry>> idMapCopy;
    // Grab cache lock to prevent any modifications
    // to the cache maps until a snapshot is taken.
    cacheLock.lock();
    try {
      // Examining the real maps will hold the lock and can cause map
      // modifications in case of any access order maps, make copies
      // instead.
      dnMapCopy = new LinkedHashMap<DN,CacheEntry>(dnMap);
      idMapCopy = new HashMap<Backend,HashMap<Long,CacheEntry>>(idMap);
    } finally {
      cacheLock.unlock();
    }
    // Check dnMap first.
    for(DN dn : dnMapCopy.keySet()) {
      verboseString = verboseString + dn.toString() + ":" +
        (dnMapCopy.get(dn) != null ?
          Long.toString(dnMapCopy.get(dn).getEntryID()) : null) +
        ":" + (dnMapCopy.get(dn) != null ?
          dnMapCopy.get(dn).getBackend().getBackendID() : null) +
        "\n";
    }
    // See if there is anything on idMap that isnt reflected on
    // dnMap in case maps went out of sync.
    for (Backend backend : idMapCopy.keySet()) {
      for (Long id : idMapCopy.get(backend).keySet()) {
        if ((idMapCopy.get(backend).get(id) == null) ||
            !dnMapCopy.containsKey(
              idMapCopy.get(backend).get(id).getDN())) {
          verboseString = verboseString +
            (idMapCopy.get(backend).get(id) != null ?
              idMapCopy.get(backend).get(id).getDN().toString() : null) +
            ":" + id.toString() + ":" + backend.getBackendID() + "\n";
        }
      }
    }
    return (verboseString.length() > 0 ? verboseString : null);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isConfigurationAcceptable(EntryCacheCfg configuration,
                                           List<Message> unacceptableReasons)
opends/src/server/org/opends/server/extensions/FileSystemEntryCache.java
@@ -662,7 +662,8 @@
    Entry entry = null;
    cacheReadLock.lock();
    try {
      if (dnMap.containsKey(entryDN)) {
      // Use get to generate entry access.
      if (dnMap.get(entryDN) != null) {
        entry = getEntryFromDB(entryDN);
      }
    } finally {
@@ -1017,6 +1018,64 @@
  /**
   * {@inheritDoc}
   */
  public String toVerboseString()
  {
    String verboseString = new String();
    Map<DN,Long> dnMapCopy;
    Map<Backend,Map<Long,DN>> backendMapCopy;
    // Grab write lock to prevent any modifications
    // to the cache maps until a snapshot is taken.
    cacheWriteLock.lock();
    try {
      // Examining the real maps will hold the lock
      // and can cause map modifications in case of
      // any access order maps, make copies instead.
      dnMapCopy = new LinkedHashMap<DN,Long>(dnMap);
      backendMapCopy =
        new LinkedHashMap<Backend,Map<Long,DN>>
          (backendMap);
    } finally {
      cacheWriteLock.unlock();
    }
    // Check dnMap first.
    for (DN dn : dnMapCopy.keySet()) {
      Backend backend = null;
      Iterator<Backend> backendIterator = backendMapCopy.keySet().iterator();
      while (backendIterator.hasNext()) {
        backend = backendIterator.next();
        Map<Long, DN> map = backendMapCopy.get(backend);
        if ((map.get(dnMapCopy.get(dn)) != null) &&
            (map.get(dnMapCopy.get(dn)).equals(dn))) {
          break;
        }
      }
    }
    // See if there is anything on backendMap that isnt reflected on dnMap
    // in case maps went out of sync.
    Backend backend = null;
    Iterator<Backend> backendIterator = backendMapCopy.keySet().iterator();
    while (backendIterator.hasNext()) {
      backend = backendIterator.next();
      Map<Long, DN> map = backendMapCopy.get(backend);
      for (Long id : map.keySet()) {
        if (!dnMapCopy.containsKey(map.get(id)) || map.get(id) == null) {
          verboseString = verboseString + (map.get(id) != null ?
            map.get(id) : null) + ":" + id.toString() + ":" +
          backend.getBackendID() + "\n";
        }
      }
    }
    return (verboseString.length() > 0 ? verboseString : null);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isConfigurationAcceptable(EntryCacheCfg configuration,
                                           List<Message> unacceptableReasons)
opends/src/server/org/opends/server/extensions/SoftReferenceEntryCache.java
@@ -282,6 +282,7 @@
    {
      map = new ConcurrentHashMap<Long,SoftReference<CacheEntry>>();
      map.put(entryID, ref);
      idMap.put(backend, map);
    }
    else
    {
@@ -361,6 +362,12 @@
          {
            ref.clear();
          }
          // If this backend becomes empty now remove
          // it from the idMap map.
          if (map.isEmpty())
          {
            idMap.remove(backend);
          }
        }
      }
    }
@@ -441,6 +448,28 @@
  /**
   * {@inheritDoc}
   */
  public String toVerboseString()
  {
    String verboseString = new String();
    // 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
    // is SoftReference based implementation.
    for(SoftReference<CacheEntry> ce : dnMap.values()) {
      verboseString = verboseString + ce.get().getDN().toString() +
        ":" + Long.toString(ce.get().getEntryID()) + ":" +
        ce.get().getBackend().getBackendID() + "\n";
    }
    return (verboseString.length() > 0 ? verboseString : null);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isConfigurationAcceptable(EntryCacheCfg configuration,
                                           List<Message> unacceptableReasons)
@@ -611,8 +640,9 @@
            {
              ref.clear();
              Backend backend = freedEntry.getBackend();
              ConcurrentHashMap<Long,SoftReference<CacheEntry>> map =
                   idMap.get(freedEntry.getBackend());
                   idMap.get(backend);
              if (map != null)
              {
                ref = map.remove(freedEntry.getEntryID());
@@ -620,6 +650,11 @@
                {
                  ref.clear();
                }
                // If this backend becomes empty now remove
                // it from the idMap map.
                if (map.isEmpty()) {
                  idMap.remove(backend);
                }
              }
            }
          }