From 6ea225b32646157c023c7e6f18e652d4d5973869 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 01 Dec 2014 10:24:31 +0000
Subject: [PATCH] OPENDJ-1602 New pluggable storage based backend

---
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java        |   13 +-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/RootContainer.java         |   20 ++-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java |   12 ++
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java        |  219 ++++++++++++++++---------------------------
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java   |    9 +
 5 files changed, 121 insertions(+), 152 deletions(-)

diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
index 71e5f8e..be3c7aa 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -27,6 +27,7 @@
  */
 package org.opends.server.backends.jeb;
 
+import java.io.Closeable;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -73,7 +74,7 @@
  * then we would not need a separate ordering index.
  */
 public class AttributeIndex
-    implements ConfigurationChangeListener<LocalDBIndexCfg>
+    implements ConfigurationChangeListener<LocalDBIndexCfg>, Closeable
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
@@ -296,13 +297,9 @@
     indexConfig.addChangeListener(this);
   }
 
-  /**
-   * Close the attribute index.
-   *
-   * @throws DatabaseException if a JE database error occurs while
-   * closing the index.
-   */
-  public void close() throws DatabaseException
+  /** Closes the attribute index. */
+  @Override
+  public void close()
   {
     Utils.closeSilently(nameToIndexes.values());
     indexConfig.removeChangeListener(this);
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
index c63e266..6c5df91 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -38,6 +38,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.util.Utils;
 import org.opends.server.admin.server.ConfigurationAddListener;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.server.ConfigurationDeleteListener;
@@ -48,16 +49,19 @@
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.EntryCache;
 import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.backends.pluggable.SuffixContainer;
 import org.opends.server.controls.*;
 import org.opends.server.core.*;
-import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.*;
 import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 
 import com.sleepycat.je.*;
 
+import static com.sleepycat.je.LockMode.*;
+
 import static org.opends.messages.JebMessages.*;
+import static org.opends.server.protocols.ldap.LDAPResultCode.*;
 import static org.opends.server.util.StaticUtils.*;
 
 /**
@@ -66,7 +70,7 @@
  * the guts of the backend API methods for LDAP operations.
  */
 public class EntryContainer
-implements ConfigurationChangeListener<LocalDBBackendCfg>
+    implements SuffixContainer, ConfigurationChangeListener<LocalDBBackendCfg>
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
@@ -90,7 +94,7 @@
   /** The vlv index configuration manager. */
   private final VLVJEIndexCfgManager vlvJEIndexCfgManager;
 
-  /** The backend to which this entry entryContainer belongs. */
+  /** The backend to which this entry container belongs. */
   private final Backend<?> backend;
 
   /** The root container in which this entryContainer belongs. */
@@ -124,6 +128,10 @@
   /** The set of VLV (Virtual List View) indexes. */
   private final HashMap<String, VLVIndex> vlvIndexMap = new HashMap<String, VLVIndex>();
 
+  /**
+   * Prevents name clashes for common indexes (like id2entry) across multiple suffixes.
+   * For example when a root container contains multiple suffixes.
+   */
   private String databasePrefix;
 
   /**
@@ -367,7 +375,7 @@
   final Lock exclusiveLock = lock.writeLock();
 
   /**
-   * Create a new entry entryContainer object.
+   * Create a new entry container object.
    *
    * @param baseDN  The baseDN this entry container will be responsible for
    *                storing on disk.
@@ -457,8 +465,7 @@
         logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backend.getBackendID());
       }
 
-      dn2uri = new DN2URI(databasePrefix + "_" + REFERRAL_DATABASE_NAME,
-          env, this);
+      dn2uri = new DN2URI(databasePrefix + "_" + REFERRAL_DATABASE_NAME, env, this);
       dn2uri.open();
 
       for (String idx : config.listLocalDBIndexes())
@@ -499,12 +506,11 @@
   }
 
   /**
-   * Closes the entry entryContainer.
+   * Closes the entry container.
    *
    * @throws DatabaseException If an error occurs in the JE database.
    */
-  public void close()
-  throws DatabaseException
+  public void close() throws DatabaseException
   {
     // Close core indexes.
     dn2id.close();
@@ -514,18 +520,14 @@
     id2subtree.close();
     state.close();
 
-    // Close attribute indexes and deregister any listeners.
-    for (AttributeIndex index : attrIndexMap.values())
-    {
-      index.close();
-    }
+    Utils.closeSilently(attrIndexMap.values());
 
-    // Close VLV indexes and deregister any listeners.
     for (VLVIndex vlvIndex : vlvIndexMap.values())
     {
       vlvIndex.close();
     }
 
+    // Deregister any listeners.
     config.removeLocalDBChangeListener(this);
     config.removeLocalDBIndexAddListener(attributeJEIndexCfgManager);
     config.removeLocalDBIndexDeleteListener(attributeJEIndexCfgManager);
@@ -546,8 +548,8 @@
   }
 
   /**
-   * Get the DN database used by this entry entryContainer. The entryContainer
-   * must have been opened.
+   * Get the DN database used by this entry container.
+   * The entryContainer must have been opened.
    *
    * @return The DN database.
    */
@@ -557,8 +559,8 @@
   }
 
   /**
-   * Get the entry database used by this entry entryContainer. The
-   * entryContainer must have been opened.
+   * Get the entry database used by this entry container.
+   * The entryContainer must have been opened.
    *
    * @return The entry database.
    */
@@ -568,8 +570,8 @@
   }
 
   /**
-   * Get the referral database used by this entry entryContainer. The
-   * entryContainer must have been opened.
+   * Get the referral database used by this entry container.
+   * The entryContainer must have been opened.
    *
    * @return The referral database.
    */
@@ -579,7 +581,7 @@
   }
 
   /**
-   * Get the children database used by this entry entryContainer.
+   * Get the children database used by this entry container.
    * The entryContainer must have been opened.
    *
    * @return The children database.
@@ -590,7 +592,7 @@
   }
 
   /**
-   * Get the subtree database used by this entry entryContainer.
+   * Get the subtree database used by this entry container.
    * The entryContainer must have been opened.
    *
    * @return The subtree database.
@@ -622,7 +624,6 @@
     return attrIndexMap.get(attrType);
   }
 
-
   /**
    * Return attribute index map.
    *
@@ -672,26 +673,23 @@
    */
   public EntryID getHighestEntryID() throws DatabaseException
   {
-    EntryID entryID = new EntryID(0);
     Cursor cursor = id2entry.openCursor(null, null);
-    DatabaseEntry key = new DatabaseEntry();
-    DatabaseEntry data = new DatabaseEntry();
-
-    // Position a cursor on the last data item, and the key should
-    // give the highest ID.
     try
     {
-      OperationStatus status = cursor.getLast(key, data, LockMode.DEFAULT);
-      if (status == OperationStatus.SUCCESS)
+      // Position a cursor on the last data item, and the key should give the highest ID.
+      DatabaseEntry key = new DatabaseEntry();
+      DatabaseEntry data = new DatabaseEntry();
+
+      if (cursor.getLast(key, data, DEFAULT) == OperationStatus.SUCCESS)
       {
-        entryID = new EntryID(key);
+        return new EntryID(key);
       }
+      return new EntryID(0);
     }
     finally
     {
       cursor.close();
     }
-    return entryID;
   }
 
   /**
@@ -763,9 +761,7 @@
          the searchResultDone message, and not send back any search result
          entries.
        */
-      searchOperation.addResponseControl(
-            new ServerSideSortResponseControl(
-                LDAPResultCode.NO_SUCH_ATTRIBUTE, null));
+      searchOperation.addResponseControl(new ServerSideSortResponseControl(NO_SUCH_ATTRIBUTE, null));
       searchOperation.setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
       return;
     }
@@ -839,23 +835,17 @@
       {
         try
         {
-          entryIDList =
-            vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest,
-                debugBuffer);
+          entryIDList = vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest, debugBuffer);
           if(entryIDList != null)
           {
-            searchOperation.addResponseControl(
-                new ServerSideSortResponseControl(LDAPResultCode.SUCCESS,
-                    null));
+            searchOperation.addResponseControl(new ServerSideSortResponseControl(SUCCESS, null));
             candidatesAreInScope = true;
             break;
           }
         }
         catch (DirectoryException de)
         {
-          searchOperation.addResponseControl(
-              new ServerSideSortResponseControl(
-                  de.getResultCode().intValue(), null));
+          searchOperation.addResponseControl(new ServerSideSortResponseControl(de.getResultCode().intValue(), null));
 
           if (sortRequest.isCritical())
           {
@@ -941,9 +931,7 @@
                 vlvRequest);
             if(sortRequest.containsSortKeys())
             {
-              searchOperation.addResponseControl(
-                new ServerSideSortResponseControl(
-                                              LDAPResultCode.SUCCESS, null));
+              searchOperation.addResponseControl(new ServerSideSortResponseControl(SUCCESS, null));
             }
             else
             {
@@ -953,16 +941,12 @@
                 server return all search results unsorted and include the
                 sortKeyResponseControl in the searchResultDone message.
               */
-              searchOperation.addResponseControl(
-                      new ServerSideSortResponseControl
-                                (LDAPResultCode.NO_SUCH_ATTRIBUTE, null));
+              searchOperation.addResponseControl(new ServerSideSortResponseControl(NO_SUCH_ATTRIBUTE, null));
             }
           }
           catch (DirectoryException de)
           {
-            searchOperation.addResponseControl(
-                new ServerSideSortResponseControl(
-                    de.getResultCode().intValue(), null));
+            searchOperation.addResponseControl(new ServerSideSortResponseControl(de.getResultCode().intValue(), null));
 
             if (sortRequest.isCritical())
             {
@@ -979,11 +963,8 @@
       debugBuffer.append(" final=");
       entryIDList.toString(debugBuffer);
 
-      Attribute attr = Attributes.create(ATTR_DEBUG_SEARCH_INDEX,
-          debugBuffer.toString());
-
-      Entry debugEntry =
-          new Entry(DN.valueOf("cn=debugsearch"), null, null, null);
+      Attribute attr = Attributes.create(ATTR_DEBUG_SEARCH_INDEX, debugBuffer.toString());
+      Entry debugEntry = new Entry(DN.valueOf("cn=debugsearch"), null, null, null);
       debugEntry.addAttribute(attr, new ArrayList<ByteString>());
 
       searchOperation.returnEntry(debugEntry, null);
@@ -996,8 +977,7 @@
       {
         rootContainer.getMonitorProvider().updateIndexedSearchCount();
       }
-      searchIndexed(entryIDList, candidatesAreInScope, searchOperation,
-          pageRequest);
+      searchIndexed(entryIDList, candidatesAreInScope, searchOperation, pageRequest);
     }
     else
     {
@@ -1006,8 +986,7 @@
         rootContainer.getMonitorProvider().updateUnindexedSearchCount();
       }
 
-      searchOperation.addAdditionalLogItem(
-          AdditionalLogItem.keyOnly(getClass(), "unindexed"));
+      searchOperation.addAdditionalLogItem(AdditionalLogItem.keyOnly(getClass(), "unindexed"));
 
       // See if we could use a virtual attribute rule to process the search.
       for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes())
@@ -1019,24 +998,18 @@
         }
       }
 
-      ClientConnection clientConnection =
-        searchOperation.getClientConnection();
-      if(! clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH,
-          searchOperation))
+      ClientConnection clientConnection = searchOperation.getClientConnection();
+      if (!clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH, searchOperation))
       {
-        LocalizableMessage message =
-          ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get();
-        throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
-            message);
+        LocalizableMessage message = ERR_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES.get();
+        throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, message);
       }
 
       if (sortRequest != null)
       {
         // FIXME -- Add support for sorting unindexed searches using indexes
         //          like DSEE currently does.
-        searchOperation.addResponseControl(
-            new ServerSideSortResponseControl(
-                LDAPResultCode.UNWILLING_TO_PERFORM, null));
+        searchOperation.addResponseControl(new ServerSideSortResponseControl(UNWILLING_TO_PERFORM, null));
 
         if (sortRequest.isCritical())
         {
@@ -1068,9 +1041,8 @@
    * @throws DirectoryException If an error prevented the search from being
    * processed.
    */
-  private void searchNotIndexed(SearchOperation searchOperation,
-      PagedResultsControl pageRequest)
-  throws DirectoryException, CanceledOperationException
+  private void searchNotIndexed(SearchOperation searchOperation, PagedResultsControl pageRequest)
+      throws DirectoryException, CanceledOperationException
   {
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     DN aBaseDN = searchOperation.getBaseDN();
@@ -1145,8 +1117,7 @@
         logger.traceException(e);
         String str = pageRequest.getCookie().toHexString();
         LocalizableMessage msg = ERR_JEB_INVALID_PAGED_RESULTS_COOKIE.get(str);
-        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
-            msg, e);
+        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg, e);
       }
     }
     else
@@ -1159,18 +1130,15 @@
     DatabaseEntry key = new DatabaseEntry(begin);
 
     int lookthroughCount = 0;
-    int lookthroughLimit =
-      searchOperation.getClientConnection().getLookthroughLimit();
+    int lookthroughLimit = searchOperation.getClientConnection().getLookthroughLimit();
 
     try
     {
       Cursor cursor = dn2id.openCursor(null, null);
       try
       {
-        OperationStatus status;
-
         // Initialize the cursor very close to the starting value.
-        status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
+        OperationStatus status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
 
         // Step forward until we pass the ending value.
         while (status == OperationStatus.SUCCESS)
@@ -1221,9 +1189,8 @@
               if ((manageDsaIT || entry.getReferralURLs() == null)
                   && searchOperation.getFilter().matchesEntry(entry))
               {
-                if (pageRequest != null &&
-                    searchOperation.getEntriesSent() ==
-                      pageRequest.getSize())
+                if (pageRequest != null
+                    && searchOperation.getEntriesSent() == pageRequest.getSize())
                 {
                   // The current page is full.
                   // Set the cookie to remember where we were.
@@ -1675,10 +1642,8 @@
       Cursor cursor = dn2id.openCursor(txn, cursorConfig);
       try
       {
-        OperationStatus status;
-
         // Initialize the cursor very close to the starting value.
-        status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
+        OperationStatus status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
 
         // Step forward until the key is greater than the starting value.
         while (status == OperationStatus.SUCCESS &&
@@ -1834,13 +1799,10 @@
       // Read the entry ID from dn2id.
       if(leafDNKey == null)
       {
-        leafDNKey =
-            new DatabaseEntry(JebFormat.dnToDNKey(
-                targetDN, this.baseDN.size()));
+        leafDNKey = new DatabaseEntry(JebFormat.dnToDNKey(targetDN, this.baseDN.size()));
       }
       DatabaseEntry value = new DatabaseEntry();
-      OperationStatus status;
-      status = dn2id.read(txn, leafDNKey, value, LockMode.RMW);
+      OperationStatus status = dn2id.read(txn, leafDNKey, value, LockMode.RMW);
       if (status != OperationStatus.SUCCESS)
       {
         LocalizableMessage message =
@@ -1964,14 +1926,13 @@
    * @throws  DirectoryException  If a problem occurs while trying to make the
    *                              determination.
    */
-  public boolean entryExists(DN entryDN)
-  throws DirectoryException
+  public boolean entryExists(DN entryDN) throws DirectoryException
   {
     // Try the entry cache first.
     EntryCache<?> entryCache = DirectoryServer.getEntryCache();
     if (entryCache != null && entryCache.containsEntry(entryDN))
     {
-        return true;
+      return true;
     }
 
     try
@@ -1983,9 +1944,8 @@
     catch (DatabaseException e)
     {
       logger.traceException(e);
+      return false;
     }
-
-    return false;
   }
 
   /**
@@ -2317,10 +2277,8 @@
       Cursor cursor = dn2id.openCursor(txn, cursorConfig);
       try
       {
-        OperationStatus status;
-
         // Initialize the cursor very close to the starting value.
-        status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
+        OperationStatus status = cursor.getSearchKeyRange(key, data, LockMode.DEFAULT);
 
         // Step forward until the key is greater than the starting value.
         while (status == OperationStatus.SUCCESS &&
@@ -2865,20 +2823,19 @@
   }
 
   /**
-   * Get a count of the number of entries stored in this entry entryContainer.
+   * Get a count of the number of entries stored in this entry container.
    *
-   * @return The number of entries stored in this entry entryContainer.
+   * @return The number of entries stored in this entry container.
    * @throws DatabaseException If an error occurs in the JE database.
    */
+  @Override
   public long getEntryCount() throws DatabaseException
   {
     EntryID entryID = dn2id.get(null, baseDN, LockMode.DEFAULT);
     if (entryID != null)
     {
-      DatabaseEntry key =
-        new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
-      EntryIDSet entryIDSet;
-      entryIDSet = id2subtree.readKey(key, null, LockMode.DEFAULT);
+      DatabaseEntry key = new DatabaseEntry(JebFormat.entryIDToDatabase(entryID.longValue()));
+      EntryIDSet entryIDSet = id2subtree.readKey(key, null, LockMode.DEFAULT);
 
       long count = entryIDSet.size();
       if(count != Long.MAX_VALUE)
@@ -2902,7 +2859,7 @@
 
   /**
    * Get the number of values for which the entry limit has been exceeded
-   * since the entry entryContainer was opened.
+   * since the entry container was opened.
    * @return The number of values for which the entry limit has been exceeded.
    */
   public int getEntryLimitExceededCount()
@@ -3247,12 +3204,8 @@
     }
   }
 
-
-  /**
-   * Get the baseDN this entry container is responsible for.
-   *
-   * @return The Base DN for this entry container.
-   */
+  /** {@inheritDoc} */
+  @Override
   public DN getBaseDN()
   {
     return baseDN;
@@ -3363,8 +3316,7 @@
    * @throws DatabaseException If an error occurs while retrieving the
    *                           configuration object.
    */
-  public EnvironmentConfig getEnvironmentConfig()
-  throws DatabaseException
+  public EnvironmentConfig getEnvironmentConfig() throws DatabaseException
   {
     return env.getConfig();
   }
@@ -3512,8 +3464,7 @@
    * @throws DirectoryException If an error prevented the check of an
    * existing entry from being performed.
    */
-  private DN getMatchedDN(DN baseDN)
-  throws DirectoryException
+  private DN getMatchedDN(DN baseDN) throws DirectoryException
   {
     DN parentDN  = baseDN.getParentDNInSuffix();
     while (parentDN != null && parentDN.isDescendantOf(getBaseDN()))
@@ -3532,22 +3483,20 @@
    */
   private void openSubordinateIndexes()
   {
-    id2children = new Index(databasePrefix + "_"
-          + ID2CHILDREN_DATABASE_NAME, new ID2CIndexer(), state,
-          config.getIndexEntryLimit(), 0, true, env, this);
-    id2children.open();
-    if (!id2children.isTrusted())
+    id2children = newIndex(ID2CHILDREN_DATABASE_NAME, new ID2CIndexer());
+    id2subtree = newIndex(ID2SUBTREE_DATABASE_NAME, new ID2SIndexer());
+  }
+
+  private Index newIndex(String name, Indexer indexer)
+  {
+    final Index index = new Index(databasePrefix + "_" + name,
+        indexer, state, config.getIndexEntryLimit(), 0, true, env, this);
+    index.open();
+    if (!index.isTrusted())
     {
-      logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, id2children.getName());
+      logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, index.getName());
     }
-    id2subtree = new Index(databasePrefix + "_" + ID2SUBTREE_DATABASE_NAME,
-            new ID2SIndexer(), state, config.getIndexEntryLimit(), 0, true,
-            env, this);
-    id2subtree.open();
-    if (!id2subtree.isTrusted())
-    {
-      logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, id2subtree.getName());
-    }
+    return index;
   }
 
 
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/RootContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/RootContainer.java
index b10db20..ab1c9bb 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/RootContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/RootContainer.java
@@ -59,7 +59,8 @@
  * of the entry containers.
  */
 public class RootContainer
-     implements ConfigurationChangeListener<LocalDBBackendCfg>
+     implements org.opends.server.backends.pluggable.RootContainer<EntryContainer>,
+                ConfigurationChangeListener<LocalDBBackendCfg>
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
@@ -78,7 +79,7 @@
   /** The database environment monitor for this JE environment. */
   private DatabaseEnvironmentMonitor monitor;
 
-  /** The base DNs contained in this entryContainer. */
+  /** The base DNs contained in this root container. */
   private final ConcurrentHashMap<DN, EntryContainer> entryContainers = new ConcurrentHashMap<DN, EntryContainer>();
 
   /** The cached value of the next entry identifier to be assigned. */
@@ -311,7 +312,6 @@
   public EntryContainer unregisterEntryContainer(DN baseDN)
   {
     return entryContainers.remove(baseDN);
-
   }
 
   /**
@@ -352,8 +352,7 @@
     if (timeLimit > 0)
     {
       // Get a list of all the databases used by the backend.
-      ArrayList<DatabaseContainer> dbList =
-          new ArrayList<DatabaseContainer>();
+      ArrayList<DatabaseContainer> dbList = new ArrayList<DatabaseContainer>();
       for (EntryContainer ec : entryContainers.values())
       {
         ec.sharedLock.lock();
@@ -441,10 +440,10 @@
   }
 
   /**
-   * Close the root entryContainer.
+   * Closes this root container.
    *
    * @throws DatabaseException If an error occurs while attempting to close
-   * the entryContainer.
+   * the root container.
    */
   public void close() throws DatabaseException
   {
@@ -482,6 +481,13 @@
     return entryContainers.values();
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public Map<DN, EntryContainer> getSuffixContainers()
+  {
+    return entryContainers;
+  }
+
   /**
    * Returns all the baseDNs this root container stores.
    *
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
index d824138..f5c96a9 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
@@ -52,4 +52,13 @@
    * @return a Map of baseDN to suffix containers
    */
   Map<DN, T> getSuffixContainers();
+
+  /**
+   * Returns the number of entries managed by all the suffix containers under
+   * this root container.
+   *
+   * @return the number of entries managed by this root container, or -1 if the
+   *         count not not be determined
+   */
+  long getEntryCount();
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
index 0e196c0..a7a1726 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
@@ -36,10 +36,18 @@
 {
 
   /**
-   * Returns the suffix's baseDN.
+   * Returns the baseDN that this suffix container is responsible for.
    *
-   * @return the suffix's baseDN
+   * @return the baseDN that this suffix container is responsible for
    */
   DN getBaseDN();
 
+  /**
+   * Returns the number of entries stored in this suffix container.
+   *
+   * @return the number of entries stored in this suffix container, or -1 if the
+   *         count not be determined
+   */
+  long getEntryCount();
+
 }

--
Gitblit v1.10.0