From 0bd57577bb85119b2b4495c5ef525ba189d8d17c Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 04 Mar 2015 23:14:55 +0000
Subject: [PATCH] OPENDJ-1848: in-line and remove various storage related access methods from DatabaseContainer.

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java               |    6 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java           |   34 +-
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java            |   22 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java               |   38 +-
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java |   32 -
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java      |    2 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java       |  345 +++++++++++++++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java              |    2 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java            |   50 +--
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java            |   20 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java      |   69 ++--
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java         |    6 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java              |   18 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java   |  154 +---------
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java               |   21 +
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java           |   23 -
 16 files changed, 515 insertions(+), 327 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index 448dff0..bc656b0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/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())
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
index 65d285c..70d2295 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
+++ b/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();
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
index 189e88f..db32aac 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2ID.java
+++ b/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);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java
index cde321c..a56afe1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DN2URI.java
+++ b/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
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java
index 2291103..05a81f6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/DatabaseContainer.java
+++ b/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();
-  }
-
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java
index b4bc534..999e242 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryCachePreloader.java
+++ b/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;
               }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
index e2a6827..4dc06d5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/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,19 +2907,13 @@
           }
         }
       });
-      storage.write(new WriteOperation()
+      // Only rename the containers if the txn succeeded.
+      for (DatabaseContainer db : databases)
       {
-        @Override
-        public void run(WriteableStorage txn) throws Exception
-        {
-          for (DatabaseContainer db : databases)
-          {
-            TreeName oldName = db.getName();
-            TreeName newName = oldName.replaceBaseDN(newBaseDN);
-            db.setName(newName);
-          }
-        }
-      });
+        TreeName oldName = db.getName();
+        TreeName newName = oldName.replaceBaseDN(newBaseDN);
+        db.setName(newName);
+      }
     }
     catch (Exception e)
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
index 97b78f1..617e913 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
+++ b/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;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
index 8dc680a..92f0268 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Importer.java
+++ b/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())
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java
index 9d9ef1d..8d10f57 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Index.java
+++ b/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;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java
index 8e5c8b7..42ec263 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/NullIndex.java
+++ b/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;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
index dfa97ab..dfb3bd3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/State.java
+++ b/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);
   }
 
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java
index a1450db..798912e 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Suffix.java
+++ b/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) {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
new file mode 100644
index 0000000..7505b0d
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
@@ -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();
+  }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
index 1a11e25..3ff4003 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VLVIndex.java
+++ b/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);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
index f656d94..40510ce 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
+++ b/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())

--
Gitblit v1.10.0