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

abobrov
18.24.2008 d5e86cdd9e41cf63e147c4811cf292fa4e7b58b7
- make the entry cache preload backend implementation specific
moving EntryCachePreloader to JEB package and reworking it
for JEB specific preload.

- scale JEB entry cache preload by unloading decoding/encoding
activities onto separate workers.

- use blocking queue to reduce in heap memory footprint, read
ahead only when necessary.

- preload entry cache with backends in read only state, holding
the server startup until the entry cache preload is complete.
1 files deleted
1 files added
15 files modified
1008 ■■■■ changed files
opends/src/messages/messages/extension.properties 33 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/Backend.java 25 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/BackupBackend.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/LDIFBackend.java 13 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MemoryBackend.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/MonitorBackend.java 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/RootDSEBackend.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java 5 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/TrustStoreBackend.java 5 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java 46 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java 418 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/TaskBackend.java 5 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/EntryCacheConfigManager.java 31 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/EntryCachePreloader.java 386 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java 5 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java 8 ●●●● patch | view | raw | blame | history
opends/src/messages/messages/extension.properties
@@ -72,20 +72,18 @@
 to initialize fifo entry cache:  %s
FATAL_ERR_SOFTREFCACHE_CANNOT_INITIALIZE_9=A fatal error occurred while \
 trying to initialize soft reference entry cache:  %s
NOTICE_CACHE_PRELOAD_PROGRESS_START_10=Starting the entry cache preload
NOTICE_CACHE_PRELOAD_PROGRESS_REPORT_11=The entry cache preload has processed \
 %d entries, %d MB free heap memory available
NOTICE_CACHE_PRELOAD_PROGRESS_DONE_12=The entry cache preload is complete \
 with the total of %d entries processed
SEVERE_WARN_CACHE_PRELOAD_INTERRUPTED_13=The entry cache preload has been \
 interrupted
SEVERE_ERR_CACHE_PRELOAD_COLLECTOR_FAILED_14=The entry cache preload was \
 unable to complete preload processing for %s backend, and as a result \
 the entry cache preload for this backend will be incomplete
SEVERE_WARN_CACHE_PRELOAD_BACKEND_FAILED_15=The entry cache preload is not \
NOTICE_CACHE_PRELOAD_PROGRESS_START_10=Starting the entry cache preload for \
 %s backend
NOTICE_CACHE_PRELOAD_PROGRESS_REPORT_11=The entry cache preload for %s backend \
 has processed %d entries, %d MB free heap memory available
NOTICE_CACHE_PRELOAD_PROGRESS_DONE_12=The entry cache preload for %s backend \
 is complete with the total of %d entries processed
SEVERE_WARN_CACHE_PRELOAD_INTERRUPTED_13=The entry cache preload for %s \
 backend has been interrupted
SEVERE_WARN_CACHE_PRELOAD_BACKEND_FAILED_14=The entry cache preload is not \
 supported by %s backend, and as a result no entries from this backend will \
 be preloaded into the entry cache
SEVERE_ERR_CACHE_PRELOAD_ENTRY_FAILED_16=Failed to preload %s entry into \
SEVERE_ERR_CACHE_PRELOAD_ENTRY_FAILED_15=Failed to preload %s entry into \
 the entry cache:  %s
MILD_ERR_EXTOP_PASSMOD_ILLEGAL_REQUEST_ELEMENT_TYPE_32=The password modify \
 extended request sequence included an ASN.1 element of an invalid type:  %s
@@ -1394,6 +1392,10 @@
 group %s references target group %s which is itself a virtual static group. \
 One virtual static group is not allowed to reference another as its target \
 group
NOTICE_FSCACHE_RESTORE_484=Staring persistent entry cache state restoration, \
 this may take awhile
NOTICE_FSCACHE_SAVE_485=Making the entry cache state persistent, this may \
 take awhile
FATAL_ERR_FSCACHE_CANNOT_INITIALIZE_486=A fatal error occurred while trying \
 to initialize file system entry cache:  %s
SEVERE_ERR_FSCACHE_CANNOT_LOAD_PERSISTENT_DATA_487=An error occurred while \
@@ -1420,10 +1422,9 @@
SEVERE_WARN_FSCACHE_OFFLINE_STATE_FAIL_496=%s backend current offline state \
 does not match persistent cache last recorded offline state. All cached data \
 for this backend is now discarded
NOTICE_FSCACHE_RESTORE_PROGRESS_REPORT_497=Restored %d cache entries of %d \
 total persistent cache entries found
NOTICE_FSCACHE_SAVE_PROGRESS_REPORT_498=Made persistent %d cache entries of %d \
 total cache entries found
NOTICE_FSCACHE_RESTORE_REPORT_497=Restored %d persistent cache entries into \
 the entry cache
NOTICE_FSCACHE_SAVE_REPORT_498=Made persistent %d cache entries
NOTICE_FSCACHE_INDEX_NOT_FOUND_499=No previous persistent cache state can be \
 found. Starting with an empty cache
SEVERE_ERR_FSCACHE_INDEX_IMPAIRED_500=The persistent cache index is \
opends/src/server/org/opends/server/api/Backend.java
@@ -30,7 +30,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -211,21 +210,18 @@
  /**
   * Retrieves the set of all DNs that are stored within this backend.
   * Note that this can be a slow operation depending on a particular
   * backend implementation and might be unsupported by some backends.
   * Attempts to pre-load all the entries stored within this backend
   * into the entry cache. Note that the caller must ensure that the
   * backend stays in read-only state until this method returns as
   * no entry locking is performed during this operation. Also note
   * that any backend implementing this method should implement pre-
   * load progress reporting and error handling specific to its own
   * implementation.
   *
   * @param   storedDNs  Collection to retrieve all stored DNs into.
   *          Note that for async operation a thread-safe collection
   *          should be used.
   *
   * @return  {@code true} if all DNs stored within this backend were
   *          successfully retrieved, or {@code false} otherwise.
   *
   * @throws  UnsupportedOperationException if backend implementation
   *          does not support this operation.
   * @throws  UnsupportedOperationException if backend does not
   *          support this operation.
   */
  public abstract boolean collectStoredDNs(Collection<DN> storedDNs)
  public abstract void preloadEntryCache()
    throws UnsupportedOperationException;
@@ -1309,4 +1305,3 @@
    return false;
  }
}
opends/src/server/org/opends/server/backends/BackupBackend.java
@@ -1303,9 +1303,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/LDIFBackend.java
@@ -29,7 +29,6 @@
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -1579,16 +1578,8 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
    backendLock.readLock().lock();
    try {
      storedDNs.addAll(entryMap.keySet());
      return true;
    } finally {
      backendLock.readLock().unlock();
    }
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/MemoryBackend.java
@@ -28,7 +28,6 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -994,11 +993,8 @@
  /**
   * {@inheritDoc}
   */
  public synchronized boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
    storedDNs.addAll(entryMap.keySet());
    return true;
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/MonitorBackend.java
@@ -29,7 +29,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -1283,10 +1282,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/RootDSEBackend.java
@@ -1535,9 +1535,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -37,7 +37,6 @@
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -5589,9 +5588,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/TrustStoreBackend.java
@@ -42,7 +42,6 @@
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -1905,9 +1904,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/backends/jeb/BackendImpl.java
@@ -25,9 +25,6 @@
 *      Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.backends.jeb;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.DatabaseEntry;
import org.opends.messages.Message;
import java.io.IOException;
@@ -42,8 +39,6 @@
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.RunRecoveryException;
import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn;
@@ -72,7 +67,6 @@
import org.opends.server.admin.std.server.LocalDBBackendCfg;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.types.DN;
import org.opends.server.backends.jeb.importLDIF.Importer;
@@ -1752,41 +1746,11 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  public void preloadEntryCache() throws
    UnsupportedOperationException
  {
    for (EntryContainer entryContainer : rootContainer.getEntryContainers()) {
      DN2ID dn2id = entryContainer.getDN2ID();
      Cursor cursor = null;
      try {
        cursor = dn2id.openCursor(null, new CursorConfig());
        DatabaseEntry key = new DatabaseEntry();
        DatabaseEntry data = new DatabaseEntry();
        OperationStatus status;
        for (status = cursor.getFirst(key, data, LockMode.DEFAULT);
             status == OperationStatus.SUCCESS;
             status = cursor.getNext(key, data, LockMode.DEFAULT)) {
          DN entryDN = DN.decode(new ASN1OctetString(key.getData()));
          storedDNs.add(entryDN);
        }
      } catch (Exception e) {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        return false;
      } finally {
        if (cursor != null) {
          try {
            cursor.close();
          } catch (DatabaseException de) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
          }
        }
      }
    }
    return true;
    EntryCachePreloader preloader =
      new EntryCachePreloader(this);
    preloader.preload();
  }
}
opends/src/server/org/opends/server/backends/jeb/EntryCachePreloader.java
New file
@@ -0,0 +1,418 @@
/*
 * 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 2008 Sun Microsystems, Inc.
 */
package org.opends.server.backends.jeb;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import java.util.Collection;
import org.opends.messages.Message;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import org.opends.server.api.DirectoryThread;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.Entry;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.messages.ExtensionMessages.*;
/**
 * This class defines a utility that will be used to pre-load the Directory
 * Server entry cache.  Pre-loader is multi-threaded and consist of the
 * following threads:
 *
 * - The Arbiter thread which monitors overall pre-load progress and manages
 *   pre-load worker threads by adding or removing them as deemed necessary.
 *
 * - The Collector thread which collects all entries stored within the
 *   backend and places them to a blocking queue workers consume from.
 *
 * - Worker threads which are responsible for monitoring the collector feed
 *   and processing the actual entries for cache storage.
 *
 * This implementation is self-adjusting to any system workload and does not
 * require any configuration parameters to optimize for initial system
 * resources availability and/or any subsequent fluctuations.
 */
class EntryCachePreloader
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * BackendImpl object.
   */
  private BackendImpl jeb;
  /**
   * Interrupt flag for the arbiter to terminate worker threads.
   */
  private AtomicBoolean interruptFlag = new AtomicBoolean(false);
  /**
   * Processed entries counter.
   */
  private AtomicLong processedEntries = new AtomicLong(0);
  /**
   * Progress report resolution.
   */
  private static final long progressInterval = 5000;
  /**
   * Default resolution time.
   */
  public static final long
    PRELOAD_DEFAULT_SLEEP_TIME = 10000;
  /**
   * Effective synchronization time.
   */
  private static long syncSleepTime;
  /**
   * Default queue capacity.
   */
  public static final int
    PRELOAD_DEFAULT_QUEUE_CAPACITY = 128;
  /**
   * Effective queue capacity.
   */
  private static int queueCapacity;
  /**
   * Worker threads.
   */
  private List<Thread> preloadThreads =
    Collections.synchronizedList(
    new LinkedList<Thread>());
  /**
   * Collector thread.
   */
  private EntryCacheCollector collector =
    new EntryCacheCollector();
  /**
   * This queue is for workers to take from.
   */
  private LinkedBlockingQueue<PreloadEntry> entryQueue;
  /**
   * The number of bytes in a megabyte.
   */
  private static final int bytesPerMegabyte = 1024*1024;
  /**
   * Constructs the Entry Cache Pre-loader for
   * a given JEB implementation instance.
   *
   * @param  jeb  The JEB instance to pre-load.
   */
  public EntryCachePreloader(BackendImpl jeb) {
    // These should not be exposed as configuration
    // parameters and are only useful for testing.
    syncSleepTime = Long.getLong(
      "org.opends.server.entrycache.preload.sleep",
      PRELOAD_DEFAULT_SLEEP_TIME);
    queueCapacity = Integer.getInteger(
      "org.opends.server.entrycache.preload.queue",
      PRELOAD_DEFAULT_QUEUE_CAPACITY);
    entryQueue =
      new LinkedBlockingQueue<PreloadEntry>(
      queueCapacity);
    this.jeb = jeb;
  }
  /**
   * The Arbiter thread.
   */
  protected void preload()
  {
    logError(NOTE_CACHE_PRELOAD_PROGRESS_START.get(jeb.getBackendID()));
    // Start collector thread first.
    collector.start();
    // Kick off a single worker.
    EntryCachePreloadWorker singleWorkerThread =
      new EntryCachePreloadWorker();
    singleWorkerThread.start();
    preloadThreads.add(singleWorkerThread);
    // Progress report timer task.
    Timer timer = new Timer();
    TimerTask progressTask = new TimerTask() {
      // Persistent state restore progress report.
      public void run() {
        if (processedEntries.get() > 0) {
          long freeMemory =
            Runtime.getRuntime().freeMemory() / bytesPerMegabyte;
          Message message = NOTE_CACHE_PRELOAD_PROGRESS_REPORT.get(
            jeb.getBackendID(), processedEntries.get(), freeMemory);
          logError(message);
        }
      }
    };
    timer.scheduleAtFixedRate(progressTask, progressInterval,
      progressInterval);
    // Cycle to monitor progress and adjust workers.
    long processedEntriesCycle = 0;
    long processedEntriesDelta = 0;
    long processedEntriesDeltaLow = 0;
    long processedEntriesDeltaHigh = 0;
    long lastKnownProcessedEntries = 0;
    try {
      while (!entryQueue.isEmpty() || collector.isAlive()) {
        Thread.sleep(syncSleepTime);
        processedEntriesCycle = processedEntries.get();
        processedEntriesDelta =
          processedEntriesCycle - lastKnownProcessedEntries;
        lastKnownProcessedEntries = processedEntriesCycle;
        // Spawn another worker if scaling up.
        if (processedEntriesDelta > processedEntriesDeltaHigh) {
          processedEntriesDeltaLow = processedEntriesDeltaHigh;
          processedEntriesDeltaHigh = processedEntriesDelta;
          EntryCachePreloadWorker workerThread =
            new EntryCachePreloadWorker();
          workerThread.start();
          preloadThreads.add(workerThread);
        }
        // Interrupt random worker if scaling down.
        if (processedEntriesDelta < processedEntriesDeltaLow) {
          processedEntriesDeltaHigh = processedEntriesDeltaLow;
          processedEntriesDeltaLow = processedEntriesDelta;
          // Leave at least one worker to progress.
          if (preloadThreads.size() > 1) {
            interruptFlag.set(true);
          }
        }
      }
      // Join the collector.
      if (collector.isAlive()) {
        collector.join();
      }
      // Join all spawned workers.
      for (Thread workerThread : preloadThreads) {
        if (workerThread.isAlive()) {
          workerThread.join();
        }
      }
      // Cancel progress report task and report done.
      timer.cancel();
      Message message = NOTE_CACHE_PRELOAD_PROGRESS_DONE.get(
        jeb.getBackendID(), processedEntries.get());
      logError(message);
    } catch (InterruptedException ex) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ex);
      }
      // Interrupt the collector.
      collector.interrupt();
      // Interrupt all preload threads.
      for (Thread thread : preloadThreads) {
        thread.interrupt();
      }
      logError(WARN_CACHE_PRELOAD_INTERRUPTED.get(
        jeb.getBackendID()));
    } finally {
      // Kill the timer task.
      timer.cancel();
    }
  }
  /**
   * The worker thread.
   */
  private class EntryCachePreloadWorker extends DirectoryThread {
    public EntryCachePreloadWorker() {
      super("Entry Cache Preload Worker");
    }
    @Override
    public void run() {
      while (!entryQueue.isEmpty() || collector.isAlive()) {
        // Check if interrupted.
        if (Thread.interrupted()) {
          return;
        }
        // Check for scaling down interruption.
        if (interruptFlag.compareAndSet(true, false)) {
          preloadThreads.remove(Thread.currentThread());
          break;
        }
        // Dequeue the next entry.
        try {
          PreloadEntry preloadEntry = entryQueue.poll();
          if (preloadEntry == null) {
            continue;
          }
          long entryID =
            JebFormat.entryIDFromDatabase(preloadEntry.entryIDBytes);
          Entry entry =
            JebFormat.entryFromDatabase(preloadEntry.entryBytes,
            jeb.getRootContainer().getCompressedSchema());
          try {
            // Even if the entry does not end up in the cache its still
            // treated as a processed entry anyways.
            DirectoryServer.getEntryCache().putEntry(entry, jeb, entryID);
            processedEntries.getAndIncrement();
          } catch (Exception ex) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, ex);
            }
            Message message = ERR_CACHE_PRELOAD_ENTRY_FAILED.get(
              entry.getDN().toNormalizedString(),
              (ex.getCause() != null ? ex.getCause().getMessage() :
                stackTraceToSingleLineString(ex)));
            logError(message);
          }
        } catch (Exception ex) {
          break;
        }
      }
    }
  }
  /**
   * The Collector thread.
   */
  private class EntryCacheCollector extends DirectoryThread {
    public EntryCacheCollector() {
      super("Entry Cache Preload Collector");
    }
    @Override
    public void run() {
      Cursor cursor = null;
      ID2Entry id2entry = null;
      DatabaseEntry key = new DatabaseEntry();
      DatabaseEntry data = new DatabaseEntry();
      Collection<EntryContainer> entryContainers =
        jeb.getRootContainer().getEntryContainers();
      Iterator<EntryContainer> ecIterator =
        entryContainers.iterator();
      OperationStatus status = OperationStatus.SUCCESS;
      try {
        while (status == OperationStatus.SUCCESS) {
          // Check if interrupted.
          if (Thread.interrupted()) {
            return;
          }
          try {
            if (cursor == null) {
              if (ecIterator.hasNext()) {
                id2entry = ecIterator.next().getID2Entry();
              } else {
                break;
              }
              if (id2entry != null) {
                cursor = id2entry.openCursor(null, new CursorConfig());
              } else {
                continue;
              }
            }
            status = cursor.getNext(key, data, LockMode.DEFAULT);
            if (status != OperationStatus.SUCCESS) {
              // Reset cursor and continue.
              if (cursor != null) {
                try {
                  cursor.close();
                } catch (DatabaseException de) {
                  if (debugEnabled()) {
                    TRACER.debugCaught(DebugLogLevel.ERROR, de);
                  }
                }
                status = OperationStatus.SUCCESS;
                cursor = null;
                continue;
              }
            } else {
              entryQueue.put(new PreloadEntry(data.getData(),
                key.getData()));
              continue;
            }
          } catch (InterruptedException e) {
            return;
          } catch (Exception e) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
          }
        }
      } finally {
        // Always close cursor.
        if (cursor != null) {
          try {
            cursor.close();
          } catch (DatabaseException de) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
          }
        }
      }
    }
  }
  /**
   * This inner class represents pre-load entry object.
   */
  private class PreloadEntry {
    // Encoded Entry.
    public byte[] entryBytes;
    // Encoded EntryID.
    public byte[] entryIDBytes;
    /**
     * Default constructor.
     */
    public PreloadEntry(byte[] entryBytes, byte[] entryIDBytes) {
      this.entryBytes = entryBytes;
      this.entryIDBytes = entryIDBytes;
    }
  }
}
opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -31,7 +31,6 @@
import java.io.File;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -1551,9 +1550,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/core/EntryCacheConfigManager.java
@@ -32,8 +32,11 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -54,15 +57,16 @@
import org.opends.server.types.ResultCode;
import org.opends.messages.MessageBuilder;
import org.opends.server.admin.std.server.EntryCacheMonitorProviderCfg;
import org.opends.server.api.Backend;
import org.opends.server.config.ConfigConstants;
import org.opends.server.config.ConfigEntry;
import org.opends.server.extensions.DefaultEntryCache;
import org.opends.server.extensions.EntryCachePreloader;
import org.opends.server.monitors.EntryCacheMonitorProvider;
import org.opends.server.types.DN;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
@@ -228,10 +232,27 @@
    }
    // If requested preload the entry cache.
    if (rootConfiguration.getGlobalConfiguration().isEntryCachePreload()) {
      // Kick off preload arbiter main thread.
      EntryCachePreloader preloadThread = new EntryCachePreloader();
      preloadThread.start();
    if (rootConfiguration.getGlobalConfiguration().isEntryCachePreload() &&
        !cacheOrderMap.isEmpty()) {
      // Preload from every active public backend.
      Map<DN, Backend> baseDNMap =
        DirectoryServer.getPublicNamingContexts();
      Set<Backend> proccessedBackends = new HashSet<Backend>();
      for (Backend backend : baseDNMap.values()) {
        if (!proccessedBackends.contains(backend)) {
          proccessedBackends.add(backend);
          try {
            backend.preloadEntryCache();
          } catch (UnsupportedOperationException ex) {
            // Some backend implementations might not support entry
            // cache preload. Log a warning and continue.
            Message message = WARN_CACHE_PRELOAD_BACKEND_FAILED.get(
              backend.getBackendID());
            logError(message);
            continue;
          }
        }
      }
    }
  }
opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -36,7 +36,6 @@
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -3622,10 +3621,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/src/server/org/opends/server/extensions/EntryCachePreloader.java
File was deleted
opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -41,7 +41,6 @@
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -1365,9 +1364,7 @@
  /**
   * {@inheritDoc}
   */
  public boolean collectStoredDNs(Collection<DN> storedDNs)
    throws UnsupportedOperationException
  {
  public void preloadEntryCache() throws UnsupportedOperationException {
    throw new UnsupportedOperationException("Operation not supported.");
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/PreloadEntryCacheTestCase.java
@@ -38,6 +38,7 @@
import org.opends.server.admin.std.meta.*;
import org.opends.server.admin.std.server.EntryCacheCfg;
import org.opends.server.admin.std.server.FileSystemEntryCacheCfg;
import org.opends.server.api.Backend;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Entry;
import org.opends.server.util.ServerConstants;
@@ -194,10 +195,9 @@
      "Expected empty cache.  " + "Cache contents:" + ServerConstants.EOL +
      toVerboseString());
    // Start pre-load and wait for it to complete.
    EntryCachePreloader preloadThread = new EntryCachePreloader();
    preloadThread.start();
    preloadThread.join();
    // Preload.
    Backend backend = DirectoryServer.getBackend("cacheTest");
    backend.preloadEntryCache();
    // Check that all test entries are preloaded.
    for(int i = 0; i < NUMTESTENTRIES; i++ ) {