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

Jean-Noel Rouvignac
02.57.2014 5905074f71d4add21a72881816b873e3053d8a37
OPENDJ-1602 New pluggable storage based backend


SuffixContainer.java:
Added simple index names, copied from EntryContainer.
Now extends Closeable.

RootContainer.java:
Now extends Closeable.

EntryContainer.java:
Referenced constants from SuffixContainer.


org.opends.server.backends.persistit: ADDED package with the following class:
PersistitBackend.java, PersistitRootContainer.java, PersistitSuffixContainer.java, PersistitDN2ID.java, PersistitID2Entry.java

KeyValueStore.java, NotImplementedException.java: ADDED

PluggableStorageBackend.java:
Updated with a few more possibilities.
4 files modified
8 files added
1435 ■■■■■ changed files
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java 13 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java 150 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java 168 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java 160 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java 316 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java 308 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java 33 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java 106 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java 51 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java 94 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java 3 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java 33 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -75,17 +75,17 @@
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The name of the entry database. */
  public static final String ID2ENTRY_DATABASE_NAME = "id2entry";
  public static final String ID2ENTRY_DATABASE_NAME = ID2ENTRY_INDEX_NAME;
  /** The name of the DN database. */
  public static final String DN2ID_DATABASE_NAME = "dn2id";
  public static final String DN2ID_DATABASE_NAME = DN2ID_INDEX_NAME;
  /** The name of the children index database. */
  private static final String ID2CHILDREN_DATABASE_NAME = "id2children";
  private static final String ID2CHILDREN_DATABASE_NAME = ID2CHILDREN_INDEX_NAME;
  /** The name of the subtree index database. */
  private static final String ID2SUBTREE_DATABASE_NAME = "id2subtree";
  private static final String ID2SUBTREE_DATABASE_NAME = ID2SUBTREE_INDEX_NAME;
  /** The name of the referral database. */
  private static final String REFERRAL_DATABASE_NAME = "referral";
  private static final String REFERRAL_DATABASE_NAME = REFERRAL_INDEX_NAME;
  /** The name of the state database. */
  private static final String STATE_DATABASE_NAME = "state";
  private static final String STATE_DATABASE_NAME = STATE_INDEX_NAME;
  /** The attribute used to return a search index debug string to the client. */
  public static final String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
@@ -510,6 +510,7 @@
   *
   * @throws DatabaseException If an error occurs in the JE database.
   */
  @Override
  public void close() throws DatabaseException
  {
    // Close core indexes.
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java
New file
@@ -0,0 +1,150 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.persistit;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.admin.std.server.LocalDBBackendCfg;
import org.opends.server.backends.pluggable.PluggableStorageBackend;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import com.persistit.exception.PersistitException;
import com.sleepycat.je.DatabaseException;
import static org.opends.messages.BackendMessages.*;
import static org.opends.messages.JebMessages.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This is an implementation of a Directory Server Backend which stores entries
 * locally in a Persistit database.
 */
public class PersistitBackend extends PluggableStorageBackend<LocalDBBackendCfg>
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  private PersistitRootContainer rootContainer;
  /**
   * Returns the root container.
   *
   * @return the root container
   */
  public PersistitRootContainer getRootContainer()
  {
    return rootContainer;
  }
  /** {@inheritDoc} */
  @Override
  public void initializeBackend() throws ConfigException, InitializationException
  {
    rootContainer = new PersistitRootContainer(this, cfg);
    rootContainer.open();
    registerBaseDNs(cfg.getBaseDN());
    cfg.addLocalDBChangeListener(this);
  }
  /** {@inheritDoc} */
  @Override
  public void finalizeBackend()
  {
    super.finalizeBackend();
    cfg.removeLocalDBChangeListener(this);
    deregisterBaseDNs(rootContainer.getSuffixContainers().keySet());
    // Close the database.
    try
    {
      rootContainer.close();
      rootContainer = null;
    }
    catch (DatabaseException e)
    {
      logger.traceException(e);
      logger.error(ERR_JEB_DATABASE_EXCEPTION, e.getMessage());
    }
    // Log an informational message.
    logger.info(NOTE_BACKEND_OFFLINE, cfg.getBackendId());
  }
  /** {@inheritDoc} */
  @Override
  public long getEntryCount()
  {
    if (rootContainer != null)
    {
      try
      {
        return rootContainer.getEntryCount();
      }
      catch (Exception e)
      {
        logger.traceException(e);
      }
    }
    return -1;
  }
  /** {@inheritDoc} */
  @Override
  public Entry getEntry(DN entryDN) throws DirectoryException
  {
    PersistitSuffixContainer sc = rootContainer.getSuffixContainer(entryDN);
    try
    {
      return sc.getEntry(entryDN);
    }
    catch (PersistitException e)
    {
      logger.traceException(e);
      throw createDirectoryException(e);
    }
  }
  /**
   * Creates a customized DirectoryException from the DatabaseException thrown
   * by JE backend.
   *
   * @param e
   *          The PersistitException to be converted.
   * @return DirectoryException created from exception.
   */
  private DirectoryException createDirectoryException(PersistitException e)
  {
    // TODO JNR rename the exception to remove the "JEB"
    LocalizableMessage message = ERR_JEB_DATABASE_EXCEPTION.get(stackTraceToSingleLineString(e));
    return new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java
New file
@@ -0,0 +1,168 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.persistit;
import org.opends.server.backends.jeb.EntryID;
import org.opends.server.backends.pluggable.KeyValueStore;
import org.opends.server.backends.pluggable.NotImplementedException;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.Transaction;
import com.persistit.Value;
import com.persistit.exception.PersistitException;
import static org.opends.server.backends.jeb.JebFormat.*;
/**
 * Persistit implementation of the DN2ID index.
 */
class PersistitDN2ID implements KeyValueStore<DN, EntryID, Transaction, Void>
{
  private static final String INDEX_NAME = SuffixContainer.ID2ENTRY_INDEX_NAME;
  private final String fullyQualifiedIndexName;
  private final PersistitSuffixContainer suffixContainer;
  private final int prefixRDNComponents;
  /**
   * Creates a new dn2id index.
   *
   * @param suffixContainer
   *          the suffix container holding this dn2id index
   */
  PersistitDN2ID(PersistitSuffixContainer suffixContainer)
  {
    this.suffixContainer = suffixContainer;
    this.fullyQualifiedIndexName = suffixContainer.getFullyQualifiedIndexName(INDEX_NAME);
    this.prefixRDNComponents = suffixContainer.getBaseDN().size();
  }
  /** {@inheritDoc} */
  @Override
  public void open() throws DirectoryException
  {
    try
    {
      this.suffixContainer.createTree(INDEX_NAME);
    }
    catch (PersistitException e)
    {
      throw new NotImplementedException(e);
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean insert(Transaction txn, DN dn, EntryID entryID) throws DirectoryException
  {
    Exchange ex = null;
    try
    {
      ex = suffixContainer.getExchange(INDEX_NAME);
      appendAll(ex.getKey(), dnToDNKey(dn, prefixRDNComponents));
      ex.getValue().put(entryID.longValue());
      ex.store();
      return true;
    }
    catch (PersistitException e)
    {
      throw new NotImplementedException(e);
    }
    finally
    {
      suffixContainer.releaseExchange(ex);
    }
  }
  private void appendAll(Key key, byte[] bytes)
  {
    if (bytes.length == 0)
    {
      // TODO JNR which is best here?
      // key.append(null);
      key.append((byte) ',');
    }
    else
    {
      // FIXME JNR this way to append is really not efficient
      for (byte b : bytes)
      {
        key.append(b);
      }
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean put(Transaction txn, DN dn, EntryID entryID) throws DirectoryException
  {
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public EntryID get(Transaction txn, DN dn, Void mode) throws DirectoryException
  {
    Exchange ex = null;
    try
    {
      ex = suffixContainer.getExchange(INDEX_NAME);
      appendAll(ex.getKey(), dnToDNKey(dn, prefixRDNComponents));
      ex.fetch();
      final Value value = ex.getValue();
      if (value.isDefined())
      {
        return new EntryID(value.getLong());
      }
      return null;
    }
    catch (PersistitException e)
    {
      throw new NotImplementedException(e);
    }
    finally
    {
      suffixContainer.releaseExchange(ex);
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean remove(Transaction txn, DN dn) throws DirectoryException
  {
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public void close()
  {
    // nothing to do
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java
New file
@@ -0,0 +1,160 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.persistit;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.api.CompressedSchema;
import org.opends.server.backends.jeb.DataConfig;
import org.opends.server.backends.jeb.EntryID;
import org.opends.server.backends.jeb.ID2Entry;
import org.opends.server.backends.pluggable.KeyValueStore;
import org.opends.server.backends.pluggable.NotImplementedException;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import com.persistit.Exchange;
import com.persistit.Value;
import com.persistit.exception.PersistitException;
/**
 * Persistit implementation of the ID2entry index.
 */
class PersistitID2Entry implements KeyValueStore<EntryID, Entry, Void, Void>
{
  // TODO JNR use com.persistit.encoding.ObjectCache when decoding attributes?
  private static final String INDEX_NAME = SuffixContainer.ID2ENTRY_INDEX_NAME;
  private final String fullyQualifiedIndexName;
  private final PersistitSuffixContainer suffixContainer;
  /** TODO JNR remove. */
  private final DataConfig dataConfig = new DataConfig(false, false, new CompressedSchema());
  /**
   * Creates a new id2entry index.
   *
   * @param suffixContainer
   *          the suffix container holding this id2entry index
   */
  PersistitID2Entry(PersistitSuffixContainer suffixContainer)
  {
    this.suffixContainer = suffixContainer;
    this.fullyQualifiedIndexName = suffixContainer.getFullyQualifiedIndexName(INDEX_NAME);
  }
  /** {@inheritDoc} */
  @Override
  public void open() throws DirectoryException
  {
    try
    {
      this.suffixContainer.createTree(INDEX_NAME);
    }
    catch (PersistitException e)
    {
      throw new NotImplementedException(e);
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean insert(Void txn, EntryID entryID, Entry entry) throws DirectoryException
  {
    Exchange ex = null;
    try
    {
      ex = suffixContainer.getExchange(INDEX_NAME);
      ex.getKey().append(entryID.longValue());
      ex.getValue().putByteArray(toByteArray(entry));
      ex.store();
      return true;
    }
    catch (PersistitException e)
    {
      throw new NotImplementedException(e);
    }
    finally
    {
      suffixContainer.releaseExchange(ex);
    }
  }
  private byte[] toByteArray(Entry entry) throws DirectoryException
  {
    ByteString bs = ID2Entry.entryToDatabase(entry, dataConfig);
    return bs.toByteArray();
  }
  /** {@inheritDoc} */
  @Override
  public boolean put(Void txn, EntryID entryID, Entry entry) throws DirectoryException
  {
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public Entry get(Void txn, EntryID entryID, Void mode) throws DirectoryException
  {
    Exchange ex = null;
    try
    {
      ex = suffixContainer.getExchange(INDEX_NAME);
      ex.getKey().append(entryID.longValue());
      ex.fetch();
      final Value value = ex.getValue();
      if (value.isDefined())
      {
        ByteString bytes = ByteString.wrap(value.getByteArray());
        CompressedSchema compressedSchema = dataConfig.getEntryEncodeConfig().getCompressedSchema();
        return ID2Entry.entryFromDatabase(bytes, compressedSchema);
      }
      return null;
    }
    catch (Exception e)
    {
      throw new NotImplementedException(e);
    }
    finally
    {
      suffixContainer.releaseExchange(ex);
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean remove(Void txn, EntryID entryID) throws DirectoryException
  {
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public void close()
  {
    // nothing to do
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java
New file
@@ -0,0 +1,316 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.persistit;
import java.io.File;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.admin.std.server.LocalDBBackendCfg;
import org.opends.server.backends.pluggable.NotImplementedException;
import org.opends.server.backends.pluggable.RootContainer;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.FilePermission;
import org.opends.server.types.InitializationException;
import com.persistit.Persistit;
import com.persistit.Volume;
import com.persistit.exception.PersistitException;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.JebMessages.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * Persistit implementation of a {@link RootContainer}.
 */
class PersistitRootContainer implements RootContainer<PersistitSuffixContainer>
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  private final PersistitBackend backend;
  private final LocalDBBackendCfg cfg;
  private Persistit db;
  /** The base DNs contained in this root container. */
  private final ConcurrentHashMap<DN, PersistitSuffixContainer> suffixContainers =
      new ConcurrentHashMap<DN, PersistitSuffixContainer>();
  /**
   * Constructor for this class.
   *
   * @param backend
   *          the persistit backend
   * @param config
   *          the configuration object
   */
  PersistitRootContainer(PersistitBackend backend, LocalDBBackendCfg config)
  {
    this.backend = backend;
    this.cfg = config;
  }
  /**
   * Returns the persistit backend.
   *
   * @return the persistit backend
   */
  public final PersistitBackend getBackend()
  {
    return backend;
  }
  /** {@inheritDoc} */
  @Override
  public Map<DN, PersistitSuffixContainer> getSuffixContainers()
  {
    return suffixContainers;
  }
  /**
   * Code copied from
   * {@link org.opends.server.backends.jeb. RootContainer#open(com.sleepycat.je.EnvironmentConfig)}
   *
   * @throws ConfigException
   *           If an configuration error occurs while creating the environment.
   */
  void open() throws ConfigException
  {
    // Determine the backend database directory.
    File parentDirectory = getFileForPath(cfg.getDBDirectory());
    File backendDirectory = new File(parentDirectory, cfg.getBackendId());
    // Create the directory if it doesn't exist.
    if (!backendDirectory.exists())
    {
      if (!backendDirectory.mkdirs())
      {
        throw new ConfigException(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
      }
    }
    // Make sure the directory is valid.
    else if (!backendDirectory.isDirectory())
    {
      throw new ConfigException(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
    }
    FilePermission backendPermission;
    try
    {
      backendPermission = FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
    }
    catch (Exception e)
    {
      throw new ConfigException(ERR_CONFIG_BACKEND_MODE_INVALID.get(cfg.dn()));
    }
    // Make sure the mode will allow the server itself access to the database
    if (!backendPermission.isOwnerWritable()
        || !backendPermission.isOwnerReadable()
        || !backendPermission.isOwnerExecutable())
    {
      throw new ConfigException(ERR_CONFIG_BACKEND_INSANE_MODE.get(cfg.getDBDirectoryPermissions()));
    }
    // Get the backend database backendDirectory permissions and apply
    if (FilePermission.canSetPermissions())
    {
      try
      {
        if (!FilePermission.setPermissions(backendDirectory, backendPermission))
        {
          logger.warn(WARN_JEB_UNABLE_SET_PERMISSIONS, backendPermission, backendDirectory);
        }
      }
      catch (Exception e)
      {
        // Log an warning that the permissions were not set.
        logger.warn(WARN_JEB_SET_PERMISSIONS_FAILED, backendDirectory, e);
      }
    }
    openAndRegisterSuffixContainers(backendDirectory);
  }
  private void openAndRegisterSuffixContainers(File backendDirectory)
  {
    DN[] baseDNs = backend.getBaseDNs();
    final Properties properties = new Properties();
    properties.setProperty("datapath", backendDirectory.toString());
    properties.setProperty("logpath", backendDirectory + "/log");
    properties.setProperty("logfile", "${logpath}/dj_${timestamp}.log");
    properties.setProperty("buffer.count.16384", "64K");
    for (int i = 0; i < baseDNs.length; i++)
    {
      // TODO JNR in the replace() down below,
      // persistit does not like commas and does not know how to escape them
      final String baseDN = toVolumeName(baseDNs[i]);
      properties.setProperty("volume." + (i + 1), "${datapath}/" + baseDN + ",create,pageSize:16K,"
          + "initialSize:50M,extensionSize:1M,maximumSize:10G");
    }
    properties.setProperty("journalpath", "${datapath}/dj_journal");
    try
    {
      db = new Persistit(properties);
      db.initialize();
      openAndRegisterSuffixContainers(baseDNs);
      if (logger.isTraceEnabled())
      {
        logger.trace("Persistit (%s) environment opened with the following config: %n%s",
            Persistit.VERSION, properties);
        // Get current size of heap in bytes
        long heapSize = Runtime.getRuntime().totalMemory();
        // Get maximum size of heap in bytes. The heap cannot grow beyond this size.
        // Any attempt will result in an OutOfMemoryException.
        long heapMaxSize = Runtime.getRuntime().maxMemory();
        // Get amount of free memory within the heap in bytes. This size will increase
        // after garbage collection and decrease as new objects are created.
        long heapFreeSize = Runtime.getRuntime().freeMemory();
        logger.trace("Current size of heap: %d bytes", heapSize);
        logger.trace("Max size of heap: %d bytes", heapMaxSize);
        logger.trace("Free memory in heap: %d bytes", heapFreeSize);
      }
    }
    catch (Exception e)
    {
      throw new NotImplementedException(e);
    }
  }
  private void openAndRegisterSuffixContainers(DN[] baseDNs) throws PersistitException, InitializationException,
      ConfigException, DirectoryException
  {
    for (DN baseDN : baseDNs)
    {
      PersistitSuffixContainer sc = openSuffixContainer(baseDN, null);
      registerSuffixContainer(baseDN, sc);
    }
  }
  private PersistitSuffixContainer openSuffixContainer(DN baseDN, String name) throws PersistitException,
      DirectoryException
  {
    String databasePrefix;
    if (name == null || name.equals(""))
    {
      databasePrefix = baseDN.toNormalizedString();
    }
    else
    {
      databasePrefix = name;
    }
    final Volume volume = db.loadVolume(toVolumeName(baseDN));
    final PersistitSuffixContainer suffixContainer =
        new PersistitSuffixContainer(baseDN, databasePrefix, this, db, volume);
    suffixContainer.open();
    return suffixContainer;
  }
  private String toVolumeName(DN dn)
  {
    return dn.toString().replace(",", "_");
  }
  private void registerSuffixContainer(DN baseDN, PersistitSuffixContainer suffixContainer)
      throws InitializationException
  {
    PersistitSuffixContainer sc = suffixContainers.get(baseDN);
    if (sc != null)
    {
      // If an entry container for this baseDN is already opened we do not allow
      // another to be opened.
      throw new InitializationException(ERR_JEB_ENTRY_CONTAINER_ALREADY_REGISTERED.get(sc.getIndexPrefix(), baseDN));
    }
    suffixContainers.put(baseDN, suffixContainer);
  }
  /** {@inheritDoc} */
  @Override
  public void close()
  {
    for (PersistitSuffixContainer sc : suffixContainers.values())
    {
      sc.close();
    }
  }
  /** {@inheritDoc} */
  @Override
  public long getEntryCount()
  {
    boolean couldDetermineAllCounts = true;
    long result = 0;
    for (SuffixContainer suffixContainer : getSuffixContainers().values())
    {
      final long suffixCount = suffixContainer.getEntryCount();
      if (suffixCount != -1)
      {
        result += suffixCount;
      }
      else
      {
        couldDetermineAllCounts = false;
      }
    }
    return couldDetermineAllCounts ? result : -1;
  }
  /**
   * Return the suffix container holding a specific DN.
   *
   * @param entryDN
   *          The DN for which to return the suffix container.
   * @return The suffix container holding the DN
   */
  PersistitSuffixContainer getSuffixContainer(DN entryDN)
  {
    PersistitSuffixContainer sc = null;
    DN nodeDN = entryDN;
    while (sc == null && nodeDN != null)
    {
      sc = suffixContainers.get(nodeDN);
      if (sc == null)
      {
        nodeDN = nodeDN.getParentDNInSuffix();
      }
    }
    return sc;
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java
New file
@@ -0,0 +1,308 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.persistit;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.api.EntryCache;
import org.opends.server.backends.jeb.EntryID;
import org.opends.server.backends.pluggable.SuffixContainer;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import com.persistit.Exchange;
import com.persistit.Persistit;
import com.persistit.Volume;
import com.persistit.exception.PersistitException;
import com.sleepycat.je.DatabaseException;
import static org.opends.messages.JebMessages.*;
/**
 * Persistit implementation of a {@link SuffixContainer}.
 */
class PersistitSuffixContainer implements SuffixContainer
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The baseDN handled by this suffix container. */
  private final DN baseDN;
  /**
   * Prevents name clashes for common indexes (like id2entry) across multiple
   * suffixes. For example when a root container contains multiple suffixes.
   */
  private final String indexPrefix;
  private final PersistitRootContainer rootContainer;
  private final Persistit db;
  private final Volume volume;
  private PersistitID2Entry id2entry;
  private PersistitDN2ID dn2id;
  /**
   * Constructor for this class.
   *
   * @param baseDN
   *          The baseDN handled by this suffix container
   * @param indexPrefix
   *          the prefix to use for indexes name
   * @param rootContainer
   *          the persisit root container
   * @param db
   *          the persisit database
   * @param volume
   *          the volume where indexes will be created
   */
  PersistitSuffixContainer(DN baseDN, String indexPrefix, PersistitRootContainer rootContainer,
      Persistit db, Volume volume)
  {
    this.baseDN = baseDN;
    this.indexPrefix = indexPrefix;
    this.rootContainer = rootContainer;
    this.db = db;
    this.volume = volume;
  }
  /**
   * Opens the entryContainer for reading and writing.
   *
   * @throws DirectoryException
   *           If an error occurs while opening the suffix container.
   */
  void open() throws DirectoryException
  {
    id2entry = new PersistitID2Entry(this);
    id2entry.open();
    dn2id = new PersistitDN2ID(this);
    dn2id.open();
  }
  /** {@inheritDoc} */
  @Override
  public void close()
  {
    dn2id.close();
    id2entry.close();
  }
  /** {@inheritDoc} */
  @Override
  public DN getBaseDN()
  {
    return baseDN;
  }
  /**
   * Returns the index name prefix.
   *
   * @return the index name prefix
   */
  public String getIndexPrefix()
  {
    return indexPrefix;
  }
  /** {@inheritDoc} */
  @Override
  public long getEntryCount()
  {
    // FIXME To be implemented
    // JNR: I have not found a suitable API to return this value
    return -1;
  }
  /**
   * Returns the id2entry index.
   *
   * @return the id2entry index
   */
  public PersistitID2Entry getID2Entry()
  {
    return id2entry;
  }
  /**
   * Creates a {@link Tree} for the fully qualified index name.
   *
   * @param fullyQualifiedIndexName
   *          The fully qualified index name
   * @throws PersistitException
   *           if a database exception happens
   */
  void createTree(String fullyQualifiedIndexName) throws PersistitException
  {
    volume.getTree(fullyQualifiedIndexName, true);
  }
  /**
   * Returns a new {@link Exchange} working on the index provided via its fully
   * qualified name.
   * <p>
   * Note: exchanges obtained with this method must be released by calling
   * {@link #releaseExchange(Exchange)}.
   *
   * @param fullyQualifiedIndexName
   *          The fully qualified index name
   * @return the exchange
   * @throws PersistitException
   *           if a database exception happens
   */
  final Exchange getExchange(String fullyQualifiedIndexName) throws PersistitException
  {
    return db.getExchange(volume, fullyQualifiedIndexName, false);
  }
  /**
   * Returns the fully qualified index name for this simple index name.
   * <p>
   * e.g.
   *
   * <pre>
   * PersistitSuffixContainer sc = ...; // initialize the suffix container
   * assertEquals(sc.getIndexPrefix(), "dccom");
   * assertEquals(sc.getFullyQualifiedIndexName("id2entry"), "dccom_id2entry");
   * </pre>
   *
   * @param simpleIndexName
   *          the simple index name to convert to a fully qualified index name
   * @return the fully qualified index name
   */
  public String getFullyQualifiedIndexName(String simpleIndexName)
  {
    return indexPrefix + "_" + simpleIndexName;
  }
  /**
   * Releases the provided exchange.
   *
   * @param exchange
   *          the exchange to release
   */
  final void releaseExchange(Exchange exchange)
  {
    if (exchange != null)
    {
      db.releaseExchange(exchange);
    }
  }
  /**
   * Indicates whether an entry with the specified DN exists.
   *
   * @param entryDN
   *          The DN of the entry for which to determine existence.
   * @return <CODE>true</CODE> if the specified entry exists, or
   *         <CODE>false</CODE> if it does not.
   * @throws DirectoryException
   *           If a problem occurs while trying to make the determination.
   */
  public boolean entryExists(DN entryDN) throws DirectoryException
  {
    // Try the entry cache first.
    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
    if (entryCache != null && entryCache.containsEntry(entryDN))
    {
      return true;
    }
    try
    {
      // Read the ID from dn2id.
      EntryID id = dn2id.get(null, entryDN, null);
      return id != null;
    }
    catch (DatabaseException e)
    {
      logger.traceException(e);
      return false;
    }
  }
  /**
   * Retrieves and returns the entry associated to the provided DN.
   *
   * @param entryDN
   *          the DN of the entry to return
   * @return the entry associated to the provided DN
   * @throws DirectoryException
   *           if a directory exception happens
   * @throws PersistitException
   *           if a database exception happens
   */
  Entry getEntry(DN entryDN) throws DirectoryException, PersistitException
  {
    EntryCache<?> entryCache = DirectoryServer.getEntryCache();
    // Try the entry cache first.
    Entry entry = null;
    if (entryCache != null)
    {
      entry = entryCache.getEntry(entryDN);
    }
    if (entry == null)
    {
      // Read dn2id.
      EntryID entryID = dn2id.get(null, entryDN, null);
      if (entryID == null)
      {
        // The entryDN does not exist.
        // Check for referral entries above the target entry.
        // TODO JNR uncomment next line
        // dn2uri.targetEntryReferrals(entryDN, null);
        return null;
      }
      // Read id2entry.
      entry = id2entry.get(null, entryID, null);
      if (entry == null)
      {
        // The entryID does not exist.
        throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), ERR_JEB_MISSING_ID2ENTRY_RECORD
            .get(entryID));
      }
      // Put the entry in the cache making sure not to overwrite
      // a newer copy that may have been inserted since the time
      // we read the cache.
      if (entryCache != null)
      {
        entryCache.putEntryIfAbsent(entry, rootContainer.getBackend(), entryID.longValue());
      }
    }
    return entry;
  }
  /** {@inheritDoc} */
  @Override
  public String toString()
  {
    return getClass().getSimpleName() + " baseDN=" + baseDN;
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java
New file
@@ -0,0 +1,33 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
/**
 * Contains the code for the Directory Server backend that uses Persistit
 * as the repository for storing entry and index information.
 */
@org.opends.server.types.PublicAPI(
     stability=org.opends.server.types.StabilityLevel.PRIVATE)
package org.opends.server.backends.persistit;
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java
New file
@@ -0,0 +1,106 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.pluggable;
import java.io.Closeable;
import org.opends.server.types.DirectoryException;
/**
 * TODO JNR.
 * @param <K> TODO JNR
 * @param <V> TODO JNR
 * @param <T> TODO JNR
 * @param <M> TODO JNR
 */
public interface KeyValueStore<K, V, T, M> extends Closeable
{
  /**
   * TODO JNR.
   *
   * @throws DirectoryException
   *           TODO JNR
   */
  void open() throws DirectoryException;
  /**
   * TODO JNR.
   *
   * @param txn
   *          TODO JNR
   * @param key
   *          TODO JNR
   * @param value
   *          TODO JNR
   * @return TODO JNR
   * @throws DirectoryException
   *           TODO JNR
   */
  boolean insert(T txn, K key, V value) throws DirectoryException;
  /**
   * TODO JNR.
   *
   * @param txn
   *          TODO JNR
   * @param key
   *          TODO JNR
   * @param value
   *          TODO JNR
   * @return TODO JNR
   * @throws DirectoryException
   *           TODO JNR
   */
  boolean put(T txn, K key, V value) throws DirectoryException;
  /**
   * TODO JNR.
   *
   * @param txn
   *          TODO JNR
   * @param key
   *          TODO JNR
   * @param mode
   *          TODO JNR
   * @return TODO JNR
   * @throws DirectoryException
   *           TODO JNR
   */
  V get(T txn, K key, M mode) throws DirectoryException;
  /**
   * TODO JNR.
   *
   * @param txn
   *          TODO JNR
   * @param key
   *          TODO JNR
   * @return TODO JNR
   * @throws DirectoryException
   *           TODO JNR
   */
  boolean remove(T txn, K key) throws DirectoryException;
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java
New file
@@ -0,0 +1,51 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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 2014 ForgeRock AS
 */
package org.opends.server.backends.pluggable;
/**
 * Class that helps figuring out where code is not implemented. This class
 * should only be used during the implementation of pluggable storage backends.
 */
public class NotImplementedException extends RuntimeException
{
  private static final long serialVersionUID = 6647576563755499711L;
  /** Default constructor. */
  public NotImplementedException()
  {
    super("Code is not implemented");
  }
  /**
   * Default constructor.
   *
   * @param cause
   *          the cause
   */
  public NotImplementedException(Throwable cause)
  {
    super("Code is not implemented", cause);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java
@@ -25,15 +25,20 @@
 */
package org.opends.server.backends.pluggable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.util.Reject;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.BackendCfg;
import org.opends.server.api.Backend;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -45,6 +50,7 @@
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.CanceledOperationException;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
@@ -64,29 +70,65 @@
 * @param <C>
 *          the type of the BackendCfg for the current backend
 */
public abstract class PluggableStorageBackend<C extends Configuration> extends Backend<C>
public abstract class PluggableStorageBackend<C extends BackendCfg>
    extends Backend<C>
    implements ConfigurationChangeListener<C>
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The configuration object. */
  protected C cfg;
  /** The set of base DNs for this backend. */
  private DN[] baseDNs;
  /** {@inheritDoc} */
  @Override
  public void configureBackend(final Configuration cfg) throws ConfigException
  public void configureBackend(final C cfg) throws ConfigException
  {
    Reject.ifNull(cfg);
    this.cfg = cfg;
    baseDNs = this.cfg.getBaseDN().toArray(new DN[0]);
  }
  /** {@inheritDoc} */
  @Override
  public void initializeBackend() throws InitializationException
  public boolean isConfigurationChangeAcceptable(C cfg, List<LocalizableMessage> unacceptableReasons)
  {
    for (DN baseDN : this.baseDNs)
    return false;
  }
  /** {@inheritDoc} */
  @Override
  public ConfigChangeResult applyConfigurationChange(C cfg)
  {
    return null;
  }
  /** {@inheritDoc} */
  @Override
  public void initializeBackend() throws ConfigException, InitializationException
  {
    registerBaseDNs(cfg.getBaseDN());
  }
  /**
   * Associates the current backend with the provided baseDNs in the directory
   * server.
   *
   * @param baseDNs
   *          the base DNs to be associated with this backend
   * @throws InitializationException
   *           If a problem occurs during initialization that is not related to
   *           the server configuration.
   */
  public void registerBaseDNs(Collection<DN> baseDNs) throws InitializationException
  {
    for (DN baseDN : baseDNs)
    {
      try
      {
        DirectoryServer.registerBaseDN(baseDN, this, true);
        DirectoryServer.registerBaseDN(baseDN, this, false);
      }
      catch (final Exception e)
      {
@@ -101,7 +143,19 @@
  {
    super.finalizeBackend();
    for (DN baseDN : this.baseDNs)
    deregisterBaseDNs(cfg.getBaseDN());
  }
  /**
   * Dissociates the current backend from the provided baseDNs in the directory
   * server.
   *
   * @param baseDNs
   *          the base DNs to dissociate from this backend
   */
  public void deregisterBaseDNs(Collection<DN> baseDNs)
  {
    for (DN baseDN : baseDNs)
    {
      try
      {
@@ -125,7 +179,7 @@
  @Override
  public void preloadEntryCache() throws UnsupportedOperationException
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -139,7 +193,7 @@
  @Override
  public boolean isIndexed(final AttributeType attributeType, final IndexType indexType)
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -151,7 +205,7 @@
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
          ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID()));
    }
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -170,7 +224,7 @@
  @Override
  public long numSubordinates(final DN entryDN, final boolean subtree) throws DirectoryException
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -210,9 +264,9 @@
  /** {@inheritDoc} */
  @Override
  public void search(final SearchOperation searchOperation) throws DirectoryException
  public void search(final SearchOperation searchOperation) throws DirectoryException, CanceledOperationException
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -263,14 +317,14 @@
  @Override
  public boolean supportsBackup()
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public boolean supportsBackup(BackupConfig backupConfig, StringBuilder unsupportedReason)
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -293,7 +347,7 @@
  @Override
  public boolean supportsRestore()
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
@@ -308,7 +362,13 @@
  @Override
  public long getEntryCount()
  {
    throw new RuntimeException("Not implemented");
    throw new NotImplementedException();
  }
  /** {@inheritDoc} */
  @Override
  public String toString()
  {
    return getClass().getSimpleName() + " baseDNs=" + Arrays.toString(baseDNs);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
@@ -24,6 +24,7 @@
 */
package org.opends.server.backends.pluggable;
import java.io.Closeable;
import java.util.Map;
import org.opends.server.types.DN;
@@ -43,7 +44,7 @@
 * @param <T>
 *          the type of the suffix containers
 */
public interface RootContainer<T extends SuffixContainer>
public interface RootContainer<T extends SuffixContainer> extends Closeable
{
  /**
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
@@ -24,6 +24,8 @@
 */
package org.opends.server.backends.pluggable;
import java.io.Closeable;
import org.opends.server.types.DN;
/**
@@ -32,10 +34,39 @@
 * stores a.k.a indexes. It stores entries in these key-values stores and
 * maintain the indexes all in sync on updates.
 */
public interface SuffixContainer
public interface SuffixContainer extends Closeable
{
  /**
   * The name of the index associating normalized DNs to ids. LDAP DNs uniquely
   * identify entries.
   */
  String DN2ID_INDEX_NAME = "dn2id";
  /**
   * The name of the index associating entry ids to entries. Entry ids are
   * monotonically increasing unique longs and entries are serialized versions
   * of LDAP entries.
   */
  String ID2ENTRY_INDEX_NAME = "id2entry";
  /**
   * The name of the index associating an entry id to the entry id set of all
   * its children.
   */
  String ID2CHILDREN_INDEX_NAME = "id2children";
  /**
   * The name of the index associating an entry id to the entry id set of all
   * its subordinates.
   */
  String ID2SUBTREE_INDEX_NAME = "id2subtree";
  /** The name of the index associating normalized DNs to normalized URIs. */
  String REFERRAL_INDEX_NAME = "referral";
  /**
   * The name of the index which associates indexes with their trust state, i.e.
   * does the index needs to be rebuilt ?
   */
  String STATE_INDEX_NAME = "state";
  /**
   * Returns the baseDN that this suffix container is responsible for.
   *
   * @return the baseDN that this suffix container is responsible for