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

Matthew Swift
05.14.2015 0bd57577bb85119b2b4495c5ef525ba189d8d17c
OPENDJ-1848: in-line and remove various storage related access methods from DatabaseContainer.

Initial refactoring work to make it easier to group calls to getRMW() and putIfAbsent() with other storage options. This will make it easier to combine them into single update() calls.

* introduced TracedStorage decorator to handle logging that was in DatabaseContainer
* DatabaseContainer: inlined and removed openCursor, delete, insert, read, and put
* temporarily split read(tree, key, isRMW) method into separate methods: read(tree, key) and readRMW(tree, key) to make it easier to track uses of RMW locking.

15 files modified
1 files added
832 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java 6 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java 21 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java 18 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java 154 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java 32 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java 59 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java 20 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java 22 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java 38 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java 23 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java 6 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java 345 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java 50 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java 34 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -264,7 +264,7 @@
   * @throws StorageRuntimeException if a JE database error occurs while
   * opening the index.
   */
  public void open(WriteableStorage txn) throws StorageRuntimeException
  void open(WriteableStorage txn) throws StorageRuntimeException
  {
    for (Index index : nameToIndexes.values())
    {
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
@@ -150,7 +150,7 @@
    this.cfg = cfg;
    baseDNs = this.cfg.getBaseDN().toArray(new DN[0]);
    storage = configureStorage(cfg);
    storage = new TracedStorage(configureStorage(cfg), cfg.getBackendId());
  }
  /** {@inheritDoc} */
@@ -969,8 +969,8 @@
  /** {@inheritDoc} */
  @Override
  public void preloadEntryCache() throws
          UnsupportedOperationException {
  public void preloadEntryCache() throws UnsupportedOperationException
  {
    EntryCachePreloader preloader = new EntryCachePreloader(this);
    preloader.preload();
  }
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
@@ -76,8 +76,7 @@
  {
    ByteString key = dnToDNKey(dn, prefixRDNComponents);
    ByteString value = id.toByteString();
    return insert(txn, key, value);
    return txn.putIfAbsent(getName(), key, value);
  }
  /**
@@ -93,7 +92,7 @@
  {
    ByteString key = dnToDNKey(dn, prefixRDNComponents);
    return delete(txn, key);
    return txn.delete(getName(), key);
  }
  /**
@@ -101,14 +100,24 @@
   * @param txn A JE database transaction to be used for the database read, or
   * null if none is required.
   * @param dn The DN for which the entry ID is desired.
   * @param isRMW whether the read operation is part of a larger read-modify-write operation
   * @return The entry ID, or null if the given DN is not in the DN database.
   * @throws StorageRuntimeException If an error occurs in the JE database.
   */
  EntryID get(ReadableStorage txn, DN dn, boolean isRMW) throws StorageRuntimeException
  EntryID get(ReadableStorage txn, DN dn) throws StorageRuntimeException
  {
    ByteString key = dnToDNKey(dn, prefixRDNComponents);
    ByteString value = read(txn, key, isRMW);
    ByteString value = txn.read(getName(), key);
    if (value != null)
    {
      return new EntryID(value);
    }
    return null;
  }
  EntryID getRMW(ReadableStorage txn, DN dn) throws StorageRuntimeException
  {
    ByteString key = dnToDNKey(dn, prefixRDNComponents);
    ByteString value = txn.getRMW(getName(), key);
    if (value != null)
    {
      return new EntryID(value);
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java
@@ -178,19 +178,19 @@
  {
    ByteString key = toKey(dn);
    ByteString oldValue = read(txn, key, true);
    ByteString oldValue = txn.getRMW(getName(), key);
    if (oldValue != null)
    {
      final Pair<DN, List<String>> dnAndUris = decode(oldValue);
      final Collection<String> newUris = dnAndUris.getSecond();
      if (newUris.addAll(labeledURIs))
      {
        put(txn, key, encode(dn, newUris));
        txn.create(getName(), key, encode(dn, newUris));
      }
    }
    else
    {
      txn.putIfAbsent(treeName, key, encode(dn, labeledURIs));
      txn.putIfAbsent(getName(), key, encode(dn, labeledURIs));
    }
    containsReferrals = ConditionResult.TRUE;
  }
@@ -209,7 +209,7 @@
  {
    ByteString key = toKey(dn);
    if (delete(txn, key))
    if (txn.delete(getName(), key))
    {
      containsReferrals = containsReferrals(txn);
      return true;
@@ -231,14 +231,14 @@
  {
    ByteString key = toKey(dn);
    ByteString oldValue = read(txn, key, true);
    ByteString oldValue = txn.getRMW(getName(), key);
    if (oldValue != null)
    {
      final Pair<DN, List<String>> dnAndUris = decode(oldValue);
      final Collection<String> oldUris = dnAndUris.getSecond();
      if (oldUris.removeAll(labeledURIs))
      {
        put(txn, key, encode(dn, oldUris));
        txn.create(getName(), key, encode(dn, oldUris));
        containsReferrals = containsReferrals(txn);
        return true;
      }
@@ -256,7 +256,7 @@
   */
  private ConditionResult containsReferrals(ReadableStorage txn)
  {
    Cursor cursor = txn.openCursor(treeName);
    Cursor cursor = txn.openCursor(getName());
    try
    {
      return ConditionResult.valueOf(cursor.next());
@@ -529,7 +529,7 @@
    try
    {
      final Cursor cursor = txn.openCursor(treeName);
      final Cursor cursor = txn.openCursor(getName());
      try
      {
        // Go up through the DIT hierarchy until we find a referral.
@@ -601,7 +601,7 @@
    try
    {
      final Cursor cursor = txn.openCursor(treeName);
      final Cursor cursor = txn.openCursor(getName());
      try
      {
        // Initialize the cursor very close to the starting value then
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java
@@ -28,17 +28,12 @@
import java.io.Closeable;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.ReadableStorage;
import org.opends.server.backends.pluggable.spi.Storage;
import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.WriteableStorage;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
/**
 * This class is a wrapper around the JE database object and provides basic
@@ -46,12 +41,11 @@
 */
abstract class DatabaseContainer implements Closeable
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The database entryContainer. */
  final EntryContainer entryContainer;
  /** The name of the database within the entryContainer. */
  TreeName treeName;
  private TreeName name;
  /** The reference to the JE Storage. */
  final Storage storage;
@@ -67,7 +61,7 @@
  {
    this.storage = storage;
    this.entryContainer = entryContainer;
    this.treeName = treeName;
    this.name = treeName;
  }
  /**
@@ -81,11 +75,8 @@
   */
  void open(WriteableStorage txn) throws StorageRuntimeException
  {
    txn.openTree(treeName);
    if (logger.isTraceEnabled())
    {
      logger.trace("JE database %s opened. txn=%s", treeName, txn);
    }
    // FIXME: remove?
    txn.openTree(name);
  }
  /**
@@ -106,83 +97,8 @@
  @Override
  public synchronized void close() throws StorageRuntimeException
  {
    storage.closeTree(treeName);
    if(logger.isTraceEnabled())
    {
      logger.trace("Closed tree %s", treeName);
    }
  }
  void put(WriteableStorage txn, ByteSequence key, ByteSequence value) throws StorageRuntimeException
  {
    txn.create(treeName, key, value);
    if (logger.isTraceEnabled())
    {
      logger.trace(messageToLog(true, treeName, txn, key, value));
    }
  }
  ByteString read(ReadableStorage txn, ByteSequence key, boolean isRMW) throws StorageRuntimeException
  {
    ByteString value = isRMW ? txn.getRMW(treeName, key) : txn.read(treeName, key);
    if (logger.isTraceEnabled())
    {
      logger.trace(messageToLog(value != null, treeName, txn, key, value));
    }
    return value;
  }
  /**
   * Insert a record into a JE database, with optional debug logging. This is a
   * simple wrapper around the JE Database.putNoOverwrite method.
   * @param txn The JE transaction handle, or null if none.
   * @param key The record key.
   * @param value The record value.
   * @return {@code true} if the key-value mapping could be inserted,
   *         {@code false} if the key was already mapped to another value
   * @throws StorageRuntimeException If an error occurs in the JE operation.
   */
  boolean insert(WriteableStorage txn, ByteString key, ByteString value) throws StorageRuntimeException
  {
    boolean result = txn.putIfAbsent(treeName, key, value);
    if (logger.isTraceEnabled())
    {
      logger.trace(messageToLog(result, treeName, txn, key, value));
    }
    return result;
  }
  /**
   * Delete a record from a JE database, with optional debug logging. This is a
   * simple wrapper around the JE Database.delete method.
   * @param txn The JE transaction handle, or null if none.
   * @param key The key of the record to be read.
   * @return {@code true} if the key mapping was removed, {@code false} otherwise
   * @throws StorageRuntimeException If an error occurs in the JE operation.
   */
  boolean delete(WriteableStorage txn, ByteSequence key) throws StorageRuntimeException
  {
    final boolean result = txn.delete(treeName, key);
    if (logger.isTraceEnabled())
    {
      logger.trace(messageToLog(result, treeName, txn, key, null));
    }
    return result;
  }
  /**
   * Open a JE cursor on the JE database.  This is a simple wrapper around
   * the JE Database.openCursor method.
   * @param txn A JE database transaction to be used by the cursor,
   * or null if none.
   * @return A JE cursor.
   * @throws StorageRuntimeException If an error occurs while attempting to open
   * the cursor.
   */
  final Cursor openCursor(ReadableStorage txn) throws StorageRuntimeException
  {
    return txn.openCursor(treeName);
    // FIXME: is this method needed?
    storage.closeTree(name);
  }
  /**
@@ -194,17 +110,11 @@
   */
  long getRecordCount(ReadableStorage txn) throws StorageRuntimeException
  {
    long count = count(txn);
    if (logger.isTraceEnabled())
    {
      logger.trace(messageToLog(true, treeName, txn, null, null));
    }
    return count;
  }
  private long count(ReadableStorage txn)
  {
    final Cursor cursor = txn.openCursor(treeName);
    /*
     * FIXME: push down to storage. Some DBs have native support for this, e.g. using counted
     * B-Trees.
     */
    final Cursor cursor = txn.openCursor(name);
    try
    {
      long count = 0;
@@ -227,7 +137,7 @@
  @Override
  public String toString()
  {
    return treeName.toString();
    return name.toString();
  }
  /**
@@ -237,7 +147,7 @@
   */
  final TreeName getName()
  {
    return treeName;
    return name;
  }
  /**
@@ -247,40 +157,6 @@
   */
  final void setName(TreeName name)
  {
    this.treeName = name;
    this.name = name;
  }
  /** Returns the message to log given the provided information. */
  private String messageToLog(boolean success, TreeName treeName, ReadableStorage txn, ByteSequence key,
      ByteSequence value)
  {
    StringBuilder builder = new StringBuilder();
    builder.append(" (");
    builder.append(success ? "SUCCESS" : "ERROR");
    builder.append(")");
    builder.append(" db=");
    builder.append(treeName);
    builder.append(" txn=");
    builder.append(txn);
    builder.append(ServerConstants.EOL);
    if (key != null)
    {
      builder.append("key:");
      builder.append(ServerConstants.EOL);
      StaticUtils.byteArrayToHexPlusAscii(builder, key.toByteArray(), 4);
    }
    // If the operation was successful we log the same common information
    // plus the data
    if (value != null)
    {
      builder.append("value(len=");
      builder.append(value.length());
      builder.append("):");
      builder.append(ServerConstants.EOL);
      StaticUtils.byteArrayToHexPlusAscii(builder, value.toByteArray(), 4);
    }
    return builder.toString();
  }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java
@@ -136,24 +136,18 @@
  private static final int bytesPerMegabyte = 1024*1024;
  /**
   * Constructs the Entry Cache Pre-loader for
   * a given JEB implementation instance.
   * Constructs the Entry Cache Pre-loader for a given JEB implementation instance.
   *
   * @param  jeb  The JEB instance to pre-load.
   * @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);
    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.backend = jeb;
  }
@@ -305,11 +299,12 @@
    public void run() {
      Cursor cursor = null;
      ID2Entry id2entry = null;
      Collection<EntryContainer> entryContainers =
        backend.getRootContainer().getEntryContainers();
      Iterator<EntryContainer> ecIterator =
        entryContainers.iterator();
      boolean success = true;
      RootContainer rootContainer = backend.getRootContainer();
      Collection<EntryContainer> entryContainers = rootContainer.getEntryContainers();
      Iterator<EntryContainer> ecIterator = entryContainers.iterator();
      // FIXME: this loop needs fixing.
      boolean success = false;
      try {
        while (success) {
@@ -325,7 +320,8 @@
                break;
              }
              if (id2entry != null) {
                cursor = id2entry.openCursor(null);
                // FIXME: "null" should be a transaction.
                // cursor = null.openCursor(id2entry.getName());
              } else {
                continue;
              }
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -747,7 +747,7 @@
        @Override
        public Long run(ReadableStorage txn) throws Exception
        {
          EntryID entryID = dn2id.get(txn, entryDN, false);
          EntryID entryID = dn2id.get(txn, entryDN);
          if (entryID != null)
          {
            ByteString key = entryID.toByteString();
@@ -928,7 +928,7 @@
            if (entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
            {
              // Read the ID from dn2id.
              EntryID baseID = dn2id.get(txn, aBaseDN, false);
              EntryID baseID = dn2id.get(txn, aBaseDN);
              if (baseID == null)
              {
                LocalizableMessage message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(aBaseDN);
@@ -1313,7 +1313,7 @@
      return cacheEntry;
    }
    final Entry entry = id2entry.get(txn, entryID, false);
    final Entry entry = id2entry.get(txn, entryID);
    if (entry != null)
    {
      // Put the entry in the cache making sure not to overwrite a newer copy
@@ -1518,7 +1518,7 @@
          try
          {
            // Check whether the entry already exists.
            if (dn2id.get(txn, entry.getName(), false) != null)
            if (dn2id.get(txn, entry.getName()) != null)
            {
              throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, ERR_JEB_ADD_ENTRY_ALREADY_EXISTS.get(entry
                  .getName()));
@@ -1532,7 +1532,7 @@
              dn2uri.targetEntryReferrals(txn, entry.getName(), null);
              // Read the parent ID from dn2id.
              parentID = dn2id.get(txn, parentDN, false);
              parentID = dn2id.get(txn, parentDN);
              if (parentID == null)
              {
                LocalizableMessage message = ERR_JEB_ADD_NO_SUCH_OBJECT.get(entry.getName());
@@ -1586,7 +1586,7 @@
              for (DN dn = getParentWithinBase(parentDN); dn != null; dn = getParentWithinBase(dn))
              {
                // Read the ID from dn2id.
                EntryID nodeID = dn2id.get(txn, dn, false);
                EntryID nodeID = dn2id.get(txn, dn);
                if (nodeID == null)
                {
                  throw new StorageRuntimeException(ERR_JEB_MISSING_DN2ID_RECORD.get(dn).toString());
@@ -1697,7 +1697,7 @@
            int subordinateEntriesDeleted = 0;
            Cursor cursor = dn2id.openCursor(txn);
            Cursor cursor = txn.openCursor(dn2id.getName());
            try
            {
              // Step forward until we pass the ending value.
@@ -1722,7 +1722,7 @@
                // Invoke any subordinate delete plugins on the entry.
                if (deleteOperation != null && !deleteOperation.isSynchronizationOperation())
                {
                  Entry subordinateEntry = id2entry.get(txn, entryID, false);
                  Entry subordinateEntry = id2entry.get(txn, entryID);
                  SubordinateDelete pluginResult =
                      getPluginConfigManager().invokeSubordinateDeletePlugins(deleteOperation, subordinateEntry);
@@ -1825,7 +1825,7 @@
      {
        leafDNKey = dnToDNKey(targetDN, baseDN.size());
      }
      ByteString value = dn2id.read(txn, leafDNKey, true);
      ByteString value = txn.getRMW(dn2id.getName(), leafDNKey);
      if (value == null)
      {
        LocalizableMessage message = ERR_JEB_DELETE_NO_SUCH_OBJECT.get(targetDN);
@@ -1836,7 +1836,7 @@
    }
    // Remove from dn2id.
    if (!dn2id.delete(txn, leafDNKey))
    if (!txn.delete(dn2id.getName(), leafDNKey))
    {
      // Do not expect to ever come through here.
      LocalizableMessage message = ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDNKey);
@@ -1845,7 +1845,7 @@
    }
    // Check that the entry exists in id2entry and read its contents.
    Entry entry = id2entry.get(txn, leafID, true);
    Entry entry = id2entry.getRMW(txn, leafID);
    if (entry == null)
    {
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
@@ -1881,7 +1881,7 @@
    parentDN = getParentWithinBase(parentDN))
    {
      // Read the ID from dn2id.
      EntryID parentID = dn2id.get(txn, parentDN, false);
      EntryID parentID = dn2id.get(txn, parentDN);
      if (parentID == null)
      {
        throw new StorageRuntimeException(ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN).toString());
@@ -1932,7 +1932,7 @@
        @Override
        public Boolean run(ReadableStorage txn) throws Exception
        {
          EntryID id = dn2id.get(null, entryDN, false);
          EntryID id = dn2id.get(null, entryDN);
        return id != null;
        }
      });
@@ -1995,7 +1995,7 @@
    try
    {
      // Read dn2id.
      EntryID entryID = dn2id.get(txn, entryDN, false);
      EntryID entryID = dn2id.get(txn, entryDN);
      if (entryID == null)
      {
        // The entryDN does not exist.
@@ -2005,7 +2005,7 @@
      }
      // Read id2entry.
      final Entry entry = id2entry.get(txn, entryID, false);
      final Entry entry = id2entry.get(txn, entryID);
      if (entry == null)
      {
        // The entryID does not exist.
@@ -2055,7 +2055,7 @@
          try
          {
            // Read dn2id.
            EntryID entryID = dn2id.get(txn, newEntry.getName(), true);
            EntryID entryID = dn2id.getRMW(txn, newEntry.getName());
            if (entryID == null)
            {
              // The entry does not exist.
@@ -2201,13 +2201,13 @@
          try
          {
            // Check whether the renamed entry already exists.
            if (!currentDN.equals(entry.getName()) && dn2id.get(txn, entry.getName(), false) != null)
            if (!currentDN.equals(entry.getName()) && dn2id.get(txn, entry.getName()) != null)
            {
              LocalizableMessage message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(entry.getName());
              throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, message);
            }
            EntryID oldApexID = dn2id.get(txn, currentDN, false);
            EntryID oldApexID = dn2id.get(txn, currentDN);
            if (oldApexID == null)
            {
              // Check for referral entries above the target entry.
@@ -2218,7 +2218,7 @@
              throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message, matchedDN, null);
            }
            Entry oldApexEntry = id2entry.get(txn, oldApexID, false);
            Entry oldApexEntry = id2entry.get(txn, oldApexID);
            if (oldApexEntry == null)
            {
              throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), ERR_JEB_MISSING_ID2ENTRY_RECORD
@@ -2238,7 +2238,7 @@
               * greater than its parent, since search results are returned in
               * ID order.
               */
              EntryID newSuperiorID = dn2id.get(txn, newSuperiorDN, false);
              EntryID newSuperiorID = dn2id.get(txn, newSuperiorDN);
              if (newSuperiorID == null)
              {
                LocalizableMessage msg = ERR_JEB_NEW_SUPERIOR_NO_SUCH_OBJECT.get(newSuperiorDN);
@@ -2297,7 +2297,7 @@
              {
                // We have found a subordinate entry.
                EntryID oldID = new EntryID(cursor.getValue());
                Entry oldEntry = id2entry.get(txn, oldID, false);
                Entry oldEntry = id2entry.get(txn, oldID);
                // Construct the new DN of the entry.
                DN newDN = modDN(oldEntry.getName(), currentDN.size(), entry.getName());
@@ -2429,7 +2429,7 @@
      for (DN dn = getParentWithinBase(newEntry.getName()); dn != null;
           dn = getParentWithinBase(dn))
      {
        EntryID parentID = dn2id.get(txn, dn, false);
        EntryID parentID = dn2id.get(txn, dn);
        ByteString parentIDKeyBytes = parentID.toByteString();
        if(isParent)
        {
@@ -2474,7 +2474,7 @@
      boolean isParent = true;
      for (DN dn = oldSuperiorDN; dn != null; dn = getParentWithinBase(dn))
      {
        EntryID parentID = dn2id.get(txn, dn, false);
        EntryID parentID = dn2id.get(txn, dn);
        ByteString parentIDKeyBytes = parentID.toByteString();
        if(isParent)
        {
@@ -2580,7 +2580,7 @@
      // Remove the old ID from id2subtree of old apex superior entries.
      for (DN dn = oldSuperiorDN; dn != null; dn = getParentWithinBase(dn))
      {
        EntryID parentID = dn2id.get(txn, dn, false);
        EntryID parentID = dn2id.get(txn, dn);
        ByteString parentIDKeyBytes = parentID.toByteString();
        id2subtree.removeID(buffer, parentIDKeyBytes, oldID);
      }
@@ -2726,7 +2726,7 @@
   */
  long getEntryCount(ReadableStorage txn) throws StorageRuntimeException
  {
    final EntryID entryID = dn2id.get(txn, baseDN, false);
    final EntryID entryID = dn2id.get(txn, baseDN);
    if (entryID != null)
    {
      final EntryIDSet entryIDSet = id2subtree.readKey(entryID.toByteString(), txn);
@@ -2893,6 +2893,7 @@
    try
    {
      // Rename in transaction.
      storage.write(new WriteOperation()
      {
        @Override
@@ -2906,11 +2907,7 @@
          }
        }
      });
      storage.write(new WriteOperation()
      {
        @Override
        public void run(WriteableStorage txn) throws Exception
        {
      // Only rename the containers if the txn succeeded.
          for (DatabaseContainer db : databases)
          {
            TreeName oldName = db.getName();
@@ -2918,8 +2915,6 @@
            db.setName(newName);
          }
        }
      });
    }
    catch (Exception e)
    {
      String msg = e.getMessage();
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
@@ -333,7 +333,7 @@
    try
    {
      ByteString value = codec.encodeInternal(entry, dataConfig);
      return insert(txn, key, value);
      return txn.putIfAbsent(getName(), key, value);
    }
    finally
    {
@@ -359,7 +359,7 @@
    try
    {
      ByteString value = codec.encodeInternal(entry, dataConfig);
      put(txn, key, value);
      txn.create(getName(), key, value);
    }
    finally
    {
@@ -377,7 +377,7 @@
   */
  boolean remove(WriteableStorage txn, EntryID id) throws StorageRuntimeException
  {
    return delete(txn, id.toByteString());
    return txn.delete(getName(), id.toByteString());
  }
  /**
@@ -385,15 +385,23 @@
   *
   * @param txn The database transaction or null if none.
   * @param id The desired entry ID which forms the key.
   * @param isRMW whether the read operation is part of a larger read-modify-write operation
   * @return The requested entry, or null if there is no such record.
   * @throws DirectoryException If a problem occurs while getting the entry.
   * @throws StorageRuntimeException If an error occurs in the JE database.
   */
  public Entry get(ReadableStorage txn, EntryID id, boolean isRMW)
  public Entry get(ReadableStorage txn, EntryID id)
       throws DirectoryException, StorageRuntimeException
  {
    ByteString value = read(txn, id.toByteString(), isRMW);
    return get0(id, txn.read(getName(), id.toByteString()));
  }
  public Entry getRMW(ReadableStorage txn, EntryID id) throws DirectoryException, StorageRuntimeException
  {
    return get0(id, txn.getRMW(getName(), id.toByteString()));
  }
  private Entry get0(EntryID id, ByteString value) throws DirectoryException
  {
    if (value == null)
    {
      return null;
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
@@ -1240,7 +1240,7 @@
        if (entryContainer != null && !suffix.getExcludeBranches().isEmpty())
        {
          logger.info(NOTE_JEB_IMPORT_MIGRATION_START, "excluded", suffix.getBaseDN());
          Cursor cursor = entryContainer.getDN2ID().openCursor(txn);
          Cursor cursor = txn.openCursor(entryContainer.getDN2ID().getName());
          try
          {
            for (DN excludedDN : suffix.getExcludeBranches())
@@ -1260,7 +1260,7 @@
                    && !importConfiguration.isCancelled() && !isCanceled)
                {
                  EntryID id = new EntryID(cursor.getValue());
                  Entry entry = entryContainer.getID2Entry().get(txn, id, false);
                  Entry entry = entryContainer.getID2Entry().get(txn, id);
                  processEntry(entry, rootContainer.getNextEntryID(), suffix);
                  migratedCount++;
                  success = cursor.next();
@@ -1303,7 +1303,7 @@
        if (entryContainer != null && !suffix.getIncludeBranches().isEmpty())
        {
          logger.info(NOTE_JEB_IMPORT_MIGRATION_START, "existing", suffix.getBaseDN());
          Cursor cursor = entryContainer.getDN2ID().openCursor(txn);
          Cursor cursor = txn.openCursor(entryContainer.getDN2ID().getName());
          try
          {
            final List<ByteString> includeBranches = includeBranchesAsBytes(suffix);
@@ -1315,7 +1315,7 @@
              if (!includeBranches.contains(key))
              {
                EntryID id = new EntryID(key);
                Entry entry = entryContainer.getID2Entry().get(txn, id, false);
                Entry entry = entryContainer.getID2Entry().get(txn, id);
                processEntry(entry, rootContainer.getNextEntryID(), suffix);
                migratedCount++;
                success = cursor.next();
@@ -1426,10 +1426,10 @@
    {
      DN entryDN = entry.getName();
      DN2ID dn2id = suffix.getDN2ID();
      EntryID oldID = dn2id.get(txn, entryDN, false);
      EntryID oldID = dn2id.get(txn, entryDN);
      if (oldID != null)
      {
        oldEntry = suffix.getID2Entry().get(txn, oldID, false);
        oldEntry = suffix.getID2Entry().get(txn, oldID);
      }
      if (oldEntry == null)
      {
@@ -1574,7 +1574,7 @@
      //the suffixes dn2id DB, then the dn cache is used.
      if (!clearedBackend)
      {
        EntryID id = suffix.getDN2ID().get(txn, entryDN, false);
        EntryID id = suffix.getDN2ID().get(txn, entryDN);
        if (id != null || !tmpEnv.insert(entryDN))
        {
          reader.rejectEntry(entry, WARN_JEB_IMPORT_ENTRY_EXISTS.get());
@@ -2208,7 +2208,7 @@
          if (parentDN != null)
          {
            ByteString key = toByteString(parentDN);
            ByteString value = entryContainer.getDN2ID().read(txn, key, false);
            ByteString value = txn.read(entryContainer.getDN2ID().getName(), key);
            if (value != null)
            {
              parentID = new EntryID(value);
@@ -2302,7 +2302,7 @@
          return parentIDMap.get(dn);
        }
        ByteString key = toByteString(dn);
        ByteString value = entryContainer.getDN2ID().read(txn, key, false);
        ByteString value = txn.read(entryContainer.getDN2ID().getName(), key);
        return value != null ? new EntryID(value) : null;
      }
@@ -2361,7 +2361,7 @@
      public void writeToDB() throws DirectoryException
      {
        entryContainer.getDN2ID().put(txn, dnKey, dnValue);
        txn.create(entryContainer.getDN2ID().getName(), dnKey, dnValue);
        indexMgr.addTotDNCount(1);
        if (parentDN != null)
        {
@@ -3001,7 +3001,7 @@
    public Void call() throws Exception
    {
      ID2Entry id2entry = entryContainer.getID2Entry();
      Cursor cursor = id2entry.openCursor(txn);
      Cursor cursor = txn.openCursor(id2entry.getName());
      try
      {
        while (cursor.next())
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java
@@ -161,18 +161,18 @@
  final void delete(WriteableStorage txn, ByteSequence key, ImportIDSet importIdSet)
      throws StorageRuntimeException
  {
    ByteString value = read(txn, key, false);
    ByteString value = txn.read(getName(), key);
    if (value != null) {
      newImportIDSet.clear();
      newImportIDSet.remove(value, importIdSet);
      if (newImportIDSet.isDefined() && newImportIDSet.size() == 0)
      {
        delete(txn, key);
        txn.delete(getName(), key);
      }
      else
      {
        value = newImportIDSet.valueToByteString();
        put(txn, key, value);
        txn.create(getName(), key, value);
      }
    } else {
      // Should never happen -- the keys should always be there.
@@ -191,7 +191,7 @@
  final void insert(WriteableStorage txn, ByteSequence key, ImportIDSet importIdSet)
      throws StorageRuntimeException
  {
    ByteString value = read(txn, key, false);
    ByteString value = txn.read(getName(), key);
    if(value != null) {
      newImportIDSet.clear();
      if (newImportIDSet.merge(value, importIdSet)) {
@@ -204,7 +204,7 @@
      }
      value = importIdSet.valueToByteString();
    }
    put(txn, key, value);
    txn.create(getName(), key, value);
  }
  void updateKey(WriteableStorage txn, ByteString key, EntryIDSet deletedIDs, EntryIDSet addedIDs)
@@ -217,12 +217,12 @@
     */
    if (deletedIDs == null && addedIDs == null)
    {
      boolean success = delete(txn, key);
      boolean success = txn.delete(getName(), key);
      if (success && logger.isTraceEnabled())
      {
        StringBuilder builder = new StringBuilder();
        StaticUtils.byteArrayToHexPlusAscii(builder, key.toByteArray(), 4);
        logger.trace("The expected key does not exist in the index %s.\nKey:%s ", treeName, builder);
        logger.trace("The expected key does not exist in the index %s.\nKey:%s ", getName(), builder);
      }
      return;
    }
@@ -243,7 +243,7 @@
       * Avoid taking a write lock on a record which has hit all IDs because it is likely to be a
       * point of contention.
       */
      ByteString value = read(txn, key, false);
      ByteString value = txn.read(getName(), key);
      if (value != null)
      {
        EntryIDSet entryIDList = new EntryIDSet(key, value);
@@ -261,7 +261,7 @@
        if ((rebuildRunning || trusted)
            && isNotNullOrEmpty(addedIDs)
            && !insert(txn, key, addedIDs.toByteString()))
            && !txn.putIfAbsent(getName(), key, addedIDs.toByteString()))
        {
          updateKeyWithRMW(txn, key, deletedIDs, addedIDs);
        }
@@ -282,21 +282,21 @@
  private void updateKeyWithRMW(WriteableStorage txn, ByteString key, EntryIDSet deletedIDs, EntryIDSet addedIDs)
      throws StorageRuntimeException
  {
    final ByteString value = read(txn, key, true);
    final ByteString value = txn.getRMW(getName(), key);
    if (value != null)
    {
      EntryIDSet entryIDList = computeEntryIDList(key, value, deletedIDs, addedIDs);
      ByteString after = entryIDList.toByteString();
      if (!after.isEmpty())
      {
        put(txn, key, after);
        txn.create(getName(), key, after);
      }
      else
      {
        // No more IDs, so remove the key. If index is not
        // trusted then this will cause all subsequent reads
        // for this key to return undefined set.
        delete(txn, key);
        txn.delete(getName(), key);
      }
    }
    else
@@ -308,7 +308,7 @@
      if ((rebuildRunning || trusted) && isNotNullOrEmpty(addedIDs))
      {
        insert(txn, key, addedIDs.toByteString());
        txn.putIfAbsent(getName(), key, addedIDs.toByteString());
      }
    }
  }
@@ -344,7 +344,7 @@
            StaticUtils.byteArrayToHexPlusAscii(builder, key.toByteArray(), 4);
            logger.trace("Index entry exceeded in index %s. " +
                "Limit: %d. ID list size: %d.\nKey:%s",
                treeName, indexEntryLimit, idCountDelta + addedIDs.size(), builder);
                getName(), indexEntryLimit, idCountDelta + addedIDs.size(), builder);
          }
        }
@@ -384,11 +384,11 @@
    {
      StringBuilder builder = new StringBuilder();
      StaticUtils.byteArrayToHexPlusAscii(builder, key.toByteArray(), 4);
      logger.trace("The expected key does not exist in the index %s.\nKey:%s", treeName, builder);
      logger.trace("The expected key does not exist in the index %s.\nKey:%s", getName(), builder);
    }
    setTrusted(txn, false);
    logger.error(ERR_JEB_INDEX_CORRUPT_REQUIRES_REBUILD, treeName);
    logger.error(ERR_JEB_INDEX_CORRUPT_REQUIRES_REBUILD, getName());
  }
  void delete(IndexBuffer buffer, ByteString keyBytes)
@@ -423,7 +423,7 @@
      return ConditionResult.UNDEFINED;
    }
    ByteString value = read(txn, key, false);
    ByteString value = txn.read(getName(), key);
    if (value != null)
    {
      EntryIDSet entryIDList = new EntryIDSet(key, value);
@@ -452,7 +452,7 @@
    try
    {
      ByteString value = read(txn, key, false);
      ByteString value = txn.read(getName(), key);
      if (value == null)
      {
        if(trusted)
@@ -512,7 +512,7 @@
      ArrayList<EntryIDSet> lists = new ArrayList<EntryIDSet>();
      Cursor cursor = txn.openCursor(treeName);
      Cursor cursor = txn.openCursor(getName());
      try
      {
        boolean success;
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java
@@ -166,29 +166,6 @@
  }
  @Override
  void put(WriteableStorage txn, ByteSequence key, ByteSequence value) throws StorageRuntimeException
  {
  }
  @Override
  ByteString read(ReadableStorage txn, ByteSequence key, boolean isRMW) throws StorageRuntimeException
  {
    return null;
  }
  @Override
  boolean insert(WriteableStorage txn, ByteString key, ByteString value) throws StorageRuntimeException
  {
    return true;
  }
  @Override
  boolean delete(WriteableStorage txn, ByteSequence key) throws StorageRuntimeException
  {
    return true;
  }
  @Override
  long getRecordCount(ReadableStorage txn) throws StorageRuntimeException
  {
    return 0;
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
@@ -80,7 +80,7 @@
  boolean removeIndexTrustState(WriteableStorage txn, DatabaseContainer index) throws StorageRuntimeException
  {
    ByteString key = keyForIndex(index);
    return delete(txn, key);
    return txn.delete(getName(), key);
  }
  /**
@@ -94,7 +94,7 @@
      throws StorageRuntimeException
  {
    ByteString key = keyForIndex(index);
    ByteString value = read(txn, key, false);
    ByteString value = txn.read(getName(), key);
    return value != null && value.equals(trueBytes);
  }
@@ -111,7 +111,7 @@
  {
    ByteString key = keyForIndex(index);
    txn.create(treeName, key, trusted ? trueBytes : falseBytes);
    txn.create(getName(), key, trusted ? trueBytes : falseBytes);
  }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java
@@ -233,7 +233,7 @@
    // or else check the dn2id database for the DN (only if backend wasn't cleared)
    final boolean parentThere = dnCache.contains(dn)
        || (!clearedBackend
            && getDN2ID().get(txn, dn, false) != null);
            && getDN2ID().get(txn, dn) != null);
    //Add the DN to the parent set if needed.
    if (parentThere) {
      synchronized(synchObject) {
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
New file
@@ -0,0 +1,345 @@
/*
 * 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 2015 ForgeRock AS
 */
package org.opends.server.backends.pluggable;
import java.io.File;
import java.io.FilenameFilter;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.Importer;
import org.opends.server.backends.pluggable.spi.ReadOperation;
import org.opends.server.backends.pluggable.spi.ReadableStorage;
import org.opends.server.backends.pluggable.spi.Storage;
import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
import org.opends.server.backends.pluggable.spi.StorageStatus;
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.UpdateFunction;
import org.opends.server.backends.pluggable.spi.WriteOperation;
import org.opends.server.backends.pluggable.spi.WriteableStorage;
/**
 * Decorates a {@link Storage} with additional trace logging.
 */
final class TracedStorage implements Storage
{
  /**
   * Decorates an {@link Importer} with additional trace logging.
   */
  private final class TracedImporter implements Importer
  {
    private final Importer importer;
    private TracedImporter(final Importer importer)
    {
      this.importer = importer;
    }
    @Override
    public void close()
    {
      importer.close();
      logger.trace("Storage.Importer.close(%s)", backendId);
    }
    @Override
    public void createTree(final TreeName name)
    {
      importer.createTree(name);
      logger.trace("Storage.Importer.createTree(%s, %s)", backendId, name);
    }
    @Override
    public void put(final TreeName name, final ByteSequence key, final ByteSequence value)
    {
      importer.put(name, key, value);
      logger.trace("Storage.Importer.put(%s, %s, %s, %s)", backendId, name, hex(key), hex(value));
    }
  }
  /**
   * Decorates an {@link ReadableStorage} with additional trace logging.
   */
  private final class TracedReadableStorage implements ReadableStorage
  {
    private final ReadableStorage txn;
    private TracedReadableStorage(final ReadableStorage txn)
    {
      this.txn = txn;
    }
    @Override
    public ByteString getRMW(final TreeName name, final ByteSequence key)
    {
      final ByteString value = txn.getRMW(name, key);
      logger.trace("Storage.ReadableStorage.getRMW(%s, %s, %s) = %s", backendId, name, hex(key), hex(value));
      return value;
    }
    @Override
    public Cursor openCursor(final TreeName name)
    {
      final Cursor cursor = txn.openCursor(name);
      logger.trace("Storage.ReadableStorage.openCursor(%s, %s)", backendId, name);
      return cursor;
    }
    @Override
    public ByteString read(final TreeName name, final ByteSequence key)
    {
      final ByteString value = txn.read(name, key);
      logger.trace("Storage.ReadableStorage.read(%s, %s, %s) = %s", backendId, name, hex(key), hex(value));
      return value;
    }
  }
  /**
   * Decorates an {@link WriteableStorage} with additional trace logging.
   */
  private final class TracedWriteableStorage implements WriteableStorage
  {
    private final WriteableStorage txn;
    private TracedWriteableStorage(final WriteableStorage txn)
    {
      this.txn = txn;
    }
    @Override
    public void create(final TreeName name, final ByteSequence key, final ByteSequence value)
    {
      txn.create(name, key, value);
      logger.trace("Storage.WriteableStorage.create(%s, %s, %s, %s)", backendId, name, hex(key), hex(value));
    }
    @Override
    public boolean delete(final TreeName name, final ByteSequence key)
    {
      final boolean isDeleted = txn.delete(name, key);
      logger.trace("Storage.WriteableStorage.delete(%s, %s, %s) = %s", backendId, name, hex(key), isDeleted);
      return isDeleted;
    }
    @Override
    public void deleteTree(final TreeName name)
    {
      txn.deleteTree(name);
      logger.trace("Storage.WriteableStorage.deleteTree(%s, %s)", backendId, name);
    }
    @Override
    public ByteString getRMW(final TreeName name, final ByteSequence key)
    {
      final ByteString value = txn.getRMW(name, key);
      logger.trace("Storage.WriteableStorage.getRMW(%s, %s, %s) = %s", backendId, name, hex(key), hex(value));
      return value;
    }
    @Override
    public Cursor openCursor(final TreeName name)
    {
      final Cursor cursor = txn.openCursor(name);
      logger.trace("Storage.WriteableStorage.openCursor(%s, %s)", backendId, name);
      return cursor;
    }
    @Override
    public void openTree(final TreeName name)
    {
      txn.openTree(name);
      logger.trace("Storage.WriteableStorage.openTree(%s, %s)", backendId, name);
    }
    @Override
    public boolean putIfAbsent(final TreeName name, final ByteSequence key, final ByteSequence value)
    {
      final boolean isCreated = txn.putIfAbsent(name, key, value);
      logger.trace("Storage.WriteableStorage.putIfAbsent(%s, %s, %s, %s) = %s", backendId, name, hex(key), hex(value),
          isCreated);
      return isCreated;
    }
    @Override
    public ByteString read(final TreeName name, final ByteSequence key)
    {
      final ByteString value = txn.read(name, key);
      logger.trace("Storage.WriteableStorage.read(%s, %s, %s) = %s", backendId, name, hex(key), hex(value));
      return value;
    }
    @Override
    public void renameTree(final TreeName oldName, final TreeName newName)
    {
      txn.renameTree(oldName, newName);
      logger.trace("Storage.WriteableStorage.renameTree(%s, %s, %s)", backendId, oldName, newName);
    }
    @Override
    public void truncateTree(final TreeName name)
    {
      txn.truncateTree(name);
      logger.trace("Storage.WriteableStorage.truncateTree(%s, %s)", backendId, name);
    }
    @Override
    public boolean update(final TreeName name, final ByteSequence key, final UpdateFunction f)
    {
      final boolean isUpdated = txn.update(name, key, f);
      logger.trace("Storage.WriteableStorage.update(%s, %s, %s, %s) = %s", backendId, name, hex(key), f, isUpdated);
      return isUpdated;
    }
  }
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  private final String backendId;
  private final Storage storage;
  TracedStorage(final Storage storage, final String backendId)
  {
    this.storage = storage;
    this.backendId = backendId;
  }
  @Override
  public void close()
  {
    storage.close();
    if (logger.isTraceEnabled())
    {
      logger.trace("Storage.close(%s)", backendId);
    }
  }
  @Override
  public void closeTree(final TreeName name)
  {
    storage.closeTree(name);
    if (logger.isTraceEnabled())
    {
      logger.trace("Storage.closeTree(%s, %s)", backendId, name);
    }
  }
  @Override
  public File getDirectory()
  {
    return storage.getDirectory();
  }
  @Override
  public FilenameFilter getFilesToBackupFilter()
  {
    return storage.getFilesToBackupFilter();
  }
  @Override
  public StorageStatus getStorageStatus()
  {
    return storage.getStorageStatus();
  }
  @Override
  public void open() throws Exception
  {
    storage.open();
    if (logger.isTraceEnabled())
    {
      logger.trace("Opened storage for backend %s", backendId);
    }
  }
  @Override
  public <T> T read(final ReadOperation<T> readOperation) throws Exception
  {
    if (logger.isTraceEnabled())
    {
      return storage.read(new ReadOperation<T>()
      {
        @Override
        public T run(final ReadableStorage txn) throws Exception
        {
          return readOperation.run(new TracedReadableStorage(txn));
        }
      });
    }
    return storage.read(readOperation);
  }
  @Override
  public void removeStorageFiles() throws StorageRuntimeException
  {
    storage.removeStorageFiles();
    if (logger.isTraceEnabled())
    {
      logger.trace("Storage.removeStorageFiles(%s)", backendId);
    }
  }
  @Override
  public Importer startImport() throws Exception
  {
    final Importer importer = storage.startImport();
    if (logger.isTraceEnabled())
    {
      logger.trace("Storage.startImport(%s)", backendId);
      return new TracedImporter(importer);
    }
    return importer;
  }
  @Override
  public boolean supportsBackupAndRestore()
  {
    return storage.supportsBackupAndRestore();
  }
  @Override
  public void write(final WriteOperation writeOperation) throws Exception
  {
    if (logger.isTraceEnabled())
    {
      storage.write(new WriteOperation()
      {
        @Override
        public void run(final WriteableStorage txn) throws Exception
        {
          writeOperation.run(new TracedWriteableStorage(txn));
        }
      });
    }
    storage.write(writeOperation);
  }
  private String hex(final ByteSequence bytes)
  {
    return bytes.toByteString().toHexString();
  }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
@@ -145,7 +145,7 @@
    catch(Exception e)
    {
      LocalizableMessage msg = ERR_JEB_CONFIG_VLV_INDEX_BAD_FILTER.get(
          config.getFilter(), treeName, stackTraceToSingleLineString(e));
          config.getFilter(), getName(), stackTraceToSingleLineString(e));
      throw new ConfigException(msg);
    }
@@ -190,7 +190,7 @@
      catch (Exception e)
      {
        throw new ConfigException(ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get(
            sortKeys[i], treeName));
            sortKeys[i], getName()));
      }
      AttributeType attrType = DirectoryServer.getAttributeType(sortAttrs[i]
@@ -198,7 +198,7 @@
      if (attrType == null)
      {
        LocalizableMessage msg = ERR_JEB_CONFIG_VLV_INDEX_UNDEFINED_ATTR.get(
            sortAttrs[i], treeName);
            sortAttrs[i], getName());
        throw new ConfigException(msg);
      }
      sortKeys[i] = new SortKey(attrType, ascending);
@@ -225,7 +225,7 @@
  {
    super.open(txn);
    final Cursor cursor = txn.openCursor(treeName);
    final Cursor cursor = txn.openCursor(getName());
    try
    {
      while (cursor.next())
@@ -408,7 +408,7 @@
  private SortValuesSet getSortValuesSet(ReadableStorage txn, ByteString key, boolean isRMW)
  {
    ByteString value = isRMW ? txn.getRMW(treeName, key) : txn.read(treeName, key);
    ByteString value = isRMW ? txn.getRMW(getName(), key) : txn.read(getName(), key);
    if (value == null)
    {
      // There are no records in the database
@@ -583,8 +583,8 @@
      if(newSize >= sortedSetCapacity)
      {
        SortValuesSet splitSortValuesSet = sortValuesSet.split(newSize / 2);
        put(txn, splitSortValuesSet.getKeyBytes(), splitSortValuesSet.toByteString()); // splitAfter
        put(txn, sortValuesSet.getKeyBytes(), sortValuesSet.toByteString()); // after
        txn.create(getName(), splitSortValuesSet.getKeyBytes(), splitSortValuesSet.toByteString()); // splitAfter
        txn.create(getName(), sortValuesSet.getKeyBytes(), sortValuesSet.toByteString()); // after
        if(logger.isTraceEnabled())
        {
@@ -597,12 +597,12 @@
      }
      else if(newSize == 0)
      {
        delete(txn, key);
        txn.delete(getName(), key);
      }
      else
      {
        ByteString after = sortValuesSet.toByteString();
        put(txn, key, after);
        txn.create(getName(), key, after);
      }
      count.getAndAdd(newSize - oldSize);
@@ -656,7 +656,7 @@
    {
      debugBuilder.append("vlv=");
      debugBuilder.append("[INDEX:");
      debugBuilder.append(treeName.getIndexId());
      debugBuilder.append(getName().getIndexId());
      debugBuilder.append("]");
    }
@@ -715,7 +715,7 @@
        int count = 1 + beforeCount + afterCount;
        selectedIDs = new long[count];
        Cursor cursor = txn.openCursor(treeName);
        Cursor cursor = txn.openCursor(getName());
        try
        {
          //Locate the set that contains the target entry.
@@ -769,7 +769,7 @@
        int includedAfterCount  = 0;
        LinkedList<EntryID> idList = new LinkedList<EntryID>();
        Cursor cursor = openCursor(txn);
        Cursor cursor = txn.openCursor(getName());
        try
        {
          ByteSequence vBytes = vlvRequest.getGreaterThanOrEqualAssertion();
@@ -884,7 +884,7 @@
      LinkedList<long[]> idSets = new LinkedList<long[]>();
      int currentCount = 0;
      Cursor cursor = openCursor(txn);
      Cursor cursor = txn.openCursor(getName());
      try
      {
        while (cursor.next())
@@ -1124,7 +1124,7 @@
    catch(Exception e)
    {
      LocalizableMessage msg = ERR_JEB_CONFIG_VLV_INDEX_BAD_FILTER.get(
              cfg.getFilter(), treeName,
              cfg.getFilter(), getName(),
              stackTraceToSingleLineString(e));
      unacceptableReasons.add(msg);
      return false;
@@ -1207,7 +1207,7 @@
      catch(Exception e)
      {
        ccr.addMessage(ERR_JEB_CONFIG_VLV_INDEX_BAD_FILTER.get(
            config.getFilter(), treeName, stackTraceToSingleLineString(e)));
            config.getFilter(), getName(), stackTraceToSingleLineString(e)));
        ccr.setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
      }
    }
@@ -1224,24 +1224,6 @@
        ccr.addMessage(e.getMessageObject());
        ccr.setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
      }
      // We have to close the database and open it using the new comparator.
      entryContainer.exclusiveLock.lock();
      try
      {
        close();
        open(txn);
      }
      catch (StorageRuntimeException de)
      {
        ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
        ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
      }
      finally
      {
        entryContainer.exclusiveLock.unlock();
      }
      ccr.setAdminActionRequired(true);
    }
@@ -1249,7 +1231,7 @@
    if (ccr.adminActionRequired())
    {
      trusted = false;
      ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(treeName));
      ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(getName()));
      try
      {
        state.putIndexTrustState(txn, this, false);
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
@@ -388,7 +388,7 @@
   */
  private void iterateID2Entry(ReadableStorage txn) throws StorageRuntimeException
  {
    Cursor cursor = id2entry.openCursor(txn);
    Cursor cursor = txn.openCursor(id2entry.getName());
    try
    {
      long storedEntryCount = id2entry.getRecordCount(txn);
@@ -499,7 +499,7 @@
   */
  private void iterateDN2ID(ReadableStorage txn) throws StorageRuntimeException
  {
    Cursor cursor = dn2id.openCursor(txn);
    Cursor cursor = txn.openCursor(dn2id.getName());
    try
    {
      while (cursor.next())
@@ -529,7 +529,7 @@
        Entry entry;
        try
        {
          entry = id2entry.get(txn, entryID, false);
          entry = id2entry.get(txn, entryID);
        }
        catch (Exception e)
        {
@@ -570,7 +570,7 @@
   */
  private void iterateID2Children(ReadableStorage txn) throws StorageRuntimeException
  {
    Cursor cursor = id2c.openCursor(txn);
    Cursor cursor = txn.openCursor(id2c.getName());
    try
    {
      while (cursor.next())
@@ -623,7 +623,7 @@
          Entry entry;
          try
          {
            entry = id2entry.get(txn, entryID, false);
            entry = id2entry.get(txn, entryID);
          }
          catch (Exception e)
          {
@@ -647,7 +647,7 @@
            Entry childEntry;
            try
            {
              childEntry = id2entry.get(txn, id, false);
              childEntry = id2entry.get(txn, id);
            }
            catch (Exception e)
            {
@@ -696,7 +696,7 @@
   */
  private void iterateID2Subtree(ReadableStorage txn) throws StorageRuntimeException
  {
    Cursor cursor = id2s.openCursor(txn);
    Cursor cursor = txn.openCursor(id2s.getName());
    try
    {
      while (cursor.next())
@@ -748,7 +748,7 @@
          Entry entry;
          try
          {
            entry = id2entry.get(txn, entryID, false);
            entry = id2entry.get(txn, entryID);
          }
          catch (Exception e)
          {
@@ -772,7 +772,7 @@
            Entry subordEntry;
            try
            {
              subordEntry = id2entry.get(txn, id, false);
              subordEntry = id2entry.get(txn, id);
            }
            catch (Exception e)
            {
@@ -880,7 +880,7 @@
      return;
    }
    Cursor cursor = vlvIndex.openCursor(txn);
    Cursor cursor = txn.openCursor(vlvIndex.getName());
    try
    {
      SortValues lastValues = null;
@@ -929,7 +929,7 @@
            EntryID id = new EntryID(values.getEntryID());
            try
            {
              entry = id2entry.get(txn, id, false);
              entry = id2entry.get(txn, id);
            }
            catch (Exception e)
            {
@@ -984,7 +984,7 @@
      return;
    }
    Cursor cursor = index.openCursor(txn);
    Cursor cursor = txn.openCursor(index.getName());
    try
    {
      while (cursor.next())
@@ -1029,7 +1029,7 @@
            Entry entry;
            try
            {
              entry = id2entry.get(txn, id, false);
              entry = id2entry.get(txn, id);
            }
            catch (Exception e)
            {
@@ -1146,7 +1146,7 @@
    // Check the ID is in dn2id with the correct DN.
    try
    {
      EntryID id = dn2id.get(txn, dn, false);
      EntryID id = dn2id.get(txn, dn);
      if (id == null)
      {
        if (logger.isTraceEnabled())
@@ -1180,7 +1180,7 @@
    {
      try
      {
        EntryID id = dn2id.get(txn, parentDN, false);
        EntryID id = dn2id.get(txn, parentDN);
        if (id == null)
        {
          if (logger.isTraceEnabled())
@@ -1218,7 +1218,7 @@
      EntryID parentID = null;
      try
      {
        parentID = dn2id.get(txn, parentDN, false);
        parentID = dn2id.get(txn, parentDN);
        if (parentID == null)
        {
          if (logger.isTraceEnabled())
@@ -1282,7 +1282,7 @@
      EntryID id = null;
      try
      {
        id = dn2id.get(txn, dn, false);
        id = dn2id.get(txn, dn);
        if (id == null)
        {
          if (logger.isTraceEnabled())