From 2a5f6206861c6a2417700cfe36a6be33a1559d58 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Mon, 27 Jul 2015 09:38:19 +0000
Subject: [PATCH] OPENDJ-2159 CR-7527 PDB Storage is read-only when using verify-index tool on Windows.

---
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java                     |    7 +
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Tree.java                         |    5 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/WriteableTransaction.java     |    5 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeStorageImporter.java   |    4 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/AccessMode.java               |   51 ++++++++++
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java               |   11 +-
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/VerifyJob.java                          |    8 +
 opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java             |    5 
 opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java |    2 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java               |   30 +++--
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java                  |    8 -
 opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java                    |    2 
 opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DN2IDTest.java                    |    2 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java                         |   58 +++++++++--
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/PersistentCompressedSchema.java   |   23 +--
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AbstractTree.java                 |    4 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeBufferImporter.java    |    6 
 opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ID2CountTest.java                 |    2 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java                |   23 ++-
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java                    |    8 +
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java                |    5 
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java                  |    4 
 22 files changed, 187 insertions(+), 86 deletions(-)

diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/VerifyJob.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/VerifyJob.java
index 4f2ea5f..566a0c1 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/VerifyJob.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/VerifyJob.java
@@ -138,7 +138,13 @@
           verifyID2Children = true;
           verifyID2Subtree = true;
         }
-        attrIndexList.addAll(entryContainer.getAttributeIndexes());
+        for (AttributeIndex index : entryContainer.getAttributeIndexes())
+        {
+          if (index.isTrusted())
+          {
+            attrIndexList.add(index);
+          }
+        }
       }
       else
       {
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
index cf2eb2d..61ab41f 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
@@ -64,6 +64,7 @@
 import org.opends.server.admin.std.server.PDBBackendCfg;
 import org.opends.server.api.Backupable;
 import org.opends.server.api.DiskSpaceMonitorHandler;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.Importer;
 import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
@@ -365,12 +366,14 @@
 
   /** Common interface for internal WriteableTransaction implementations. */
   private interface StorageImpl extends WriteableTransaction, Closeable {
+
   }
 
   /** PersistIt implementation of the {@link WriteableTransaction} interface. */
   private final class WriteableStorageImpl implements StorageImpl
   {
     private final Map<TreeName, Exchange> exchanges = new HashMap<>();
+    private final String DUMMY_RECORD = "_DUMMY_RECORD_";
 
     @Override
     public void put(final TreeName treeName, final ByteSequence key, final ByteSequence value)
@@ -462,20 +465,22 @@
     }
 
     @Override
-    public void openTree(final TreeName treeName)
+    public void openTree(final TreeName treeName, boolean createOnDemand)
     {
-      Exchange ex = null;
-      try
+      if (createOnDemand)
       {
-        ex = getNewExchange(treeName, true);
+        openCreateTree(treeName);
       }
-      catch (final PersistitException e)
+      else
       {
-        throw new StorageRuntimeException(e);
-      }
-      finally
-      {
-        db.releaseExchange(ex);
+        try
+        {
+          getExchangeFromCache(treeName);
+        }
+        catch (final PersistitException e)
+        {
+          throw new StorageRuntimeException(e);
+        }
       }
     }
 
@@ -532,6 +537,28 @@
       }
     }
 
+    private void openCreateTree(final TreeName treeName)
+    {
+      Exchange ex = null;
+      try
+      {
+        ex = getNewExchange(treeName, true);
+        // Work around a problem with forced shutdown right after tree creation.
+        // Tree operations are not part of the journal, so force a couple operations to be able to recover.
+        ByteString dummyKey = ByteString.valueOf(DUMMY_RECORD);
+        put(treeName, dummyKey, ByteString.empty());
+        delete(treeName, dummyKey);
+      }
+      catch (final PersistitException e)
+      {
+        throw new StorageRuntimeException(e);
+      }
+      finally
+      {
+        db.releaseExchange(ex);
+      }
+    }
+
     private Exchange getExchangeFromCache(final TreeName treeName) throws PersistitException
     {
       Exchange exchange = exchanges.get(treeName);
@@ -583,8 +610,12 @@
     }
 
     @Override
-    public void openTree(TreeName treeName)
+    public void openTree(TreeName treeName, boolean createOnDemand)
     {
+      if (createOnDemand)
+      {
+        throw new ReadOnlyStorageException();
+      }
       Exchange ex = null;
       try
       {
@@ -592,7 +623,7 @@
       }
       catch (final TreeNotFoundException e)
       {
-        throw new ReadOnlyStorageException();
+        // ignore missing trees.
       }
       catch (final PersistitException e)
       {
@@ -648,7 +679,7 @@
 
   private StorageImpl newStorageImpl() {
     final WriteableStorageImpl writeableStorage = new WriteableStorageImpl();
-    return accessMode.equals(AccessMode.READ_ONLY) ? new ReadOnlyStorageImpl(writeableStorage) : writeableStorage;
+    return accessMode.isWriteable() ? writeableStorage : new ReadOnlyStorageImpl(writeableStorage);
   }
 
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@@ -689,6 +720,7 @@
     dbCfg.setLogFile(new File(backendDirectory, VOLUME_NAME + ".log").getPath());
     dbCfg.setJournalPath(new File(backendDirectory, JOURNAL_NAME).getPath());
     dbCfg.setCheckpointInterval(config.getDBCheckpointerWakeupInterval());
+    // Volume is opened read write because recovery will fail if opened read-only
     dbCfg.setVolumeList(asList(new VolumeSpecification(new File(backendDirectory, VOLUME_NAME).getPath(), null,
         BUFFER_SIZE, 4096, Long.MAX_VALUE / BUFFER_SIZE, 2048, true, false, false)));
     final BufferPoolConfiguration bufferPoolCfg = getBufferPoolCfg(dbCfg);
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AbstractTree.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AbstractTree.java
index eb7ff57..0c2f8b3 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AbstractTree.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AbstractTree.java
@@ -46,9 +46,9 @@
   }
 
   @Override
-  public final void open(WriteableTransaction txn) throws StorageRuntimeException
+  public final void open(WriteableTransaction txn, boolean createOnDemand) throws StorageRuntimeException
   {
-    txn.openTree(name);
+    txn.openTree(name, createOnDemand);
     open0(txn);
   }
 
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index 3ab3628..9393763 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -334,13 +334,14 @@
    * Open the attribute index.
    *
    * @param txn a non null transaction
+   * @param createOnDemand true if the tree should be created if it does not exist
    * @throws StorageRuntimeException if an error occurs while opening the index
    */
-  void open(WriteableTransaction txn) throws StorageRuntimeException
+  void open(WriteableTransaction txn, boolean createOnDemand) throws StorageRuntimeException
   {
     for (Index index : indexIdToIndexes.values())
     {
-      index.open(txn);
+      index.open(txn, createOnDemand);
     }
     config.addChangeListener(this);
   }
@@ -761,7 +762,7 @@
         {
           for (MatchingRuleIndex addedIndex : addedIndexes.values())
           {
-            openIndex(txn, addedIndex, ccr);
+            createIndex(txn, addedIndex, ccr);
           }
         }
       });
@@ -805,9 +806,9 @@
     return ccr;
   }
 
-  private static void openIndex(WriteableTransaction txn, MatchingRuleIndex index, ConfigChangeResult ccr)
+  private static void createIndex(WriteableTransaction txn, MatchingRuleIndex index, ConfigChangeResult ccr)
   {
-    index.open(txn);
+    index.open(txn, true);
     if (!index.isTrusted())
     {
       ccr.setAdminActionRequired(true);
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
index 0fced90..d0c12d9 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
@@ -54,8 +54,8 @@
 import org.opends.server.backends.RebuildConfig;
 import org.opends.server.backends.VerifyConfig;
 import org.opends.server.backends.pluggable.ImportSuffixCommand.SuffixImportStrategy;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.StorageInUseException;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
@@ -946,7 +946,7 @@
         try
         {
           // The base DN was added.
-          EntryContainer ec = rootContainer.openEntryContainer(baseDN, txn);
+          EntryContainer ec = rootContainer.openEntryContainer(baseDN, txn, AccessMode.READ_WRITE);
           rootContainer.registerEntryContainer(baseDN, ec);
           DirectoryServer.registerBaseDN(baseDN, this, false);
         }
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
index 8022d4b..0ceece0 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -73,6 +73,7 @@
 import org.opends.server.api.VirtualAttributeProvider;
 import org.opends.server.api.plugin.PluginResult.SubordinateDelete;
 import org.opends.server.api.plugin.PluginResult.SubordinateModifyDN;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
@@ -217,7 +218,7 @@
           @Override
           public void run(WriteableTransaction txn) throws Exception
           {
-            index.open(txn);
+            index.open(txn, true);
             if (!index.isTrusted())
             {
               ccr.setAdminActionRequired(true);
@@ -353,7 +354,7 @@
           public void run(WriteableTransaction txn) throws Exception
           {
             VLVIndex vlvIndex = new VLVIndex(cfg, state, storage, EntryContainer.this, txn);
-            vlvIndex.open(txn);
+            vlvIndex.open(txn, true);
             if(!vlvIndex.isTrusted())
             {
               ccr.setAdminActionRequired(true);
@@ -461,11 +462,13 @@
    * Opens the entryContainer for reading and writing.
    *
    * @param txn a non null transaction
+   * @param accessMode specifies how the container has to be opened (read-write or read-only)
    * @throws StorageRuntimeException If an error occurs in the storage.
    * @throws ConfigException if a configuration related error occurs.
    */
-  void open(WriteableTransaction txn) throws StorageRuntimeException, ConfigException
+  void open(WriteableTransaction txn, AccessMode accessMode) throws StorageRuntimeException, ConfigException
   {
+    boolean shouldCreate = accessMode.isWriteable();
     try
     {
       DataConfig entryDataConfig =
@@ -474,18 +477,18 @@
             rootContainer.getCompressedSchema());
 
       id2entry = new ID2Entry(getIndexName(ID2ENTRY_TREE_NAME), entryDataConfig);
-      id2entry.open(txn);
-      id2childrenCount.open(txn);
-      dn2id.open(txn);
-      state.open(txn);
-      dn2uri.open(txn);
+      id2entry.open(txn, shouldCreate);
+      id2childrenCount.open(txn, shouldCreate);
+      dn2id.open(txn, shouldCreate);
+      state.open(txn, shouldCreate);
+      dn2uri.open(txn, shouldCreate);
 
       for (String idx : config.listBackendIndexes())
       {
         BackendIndexCfg indexCfg = config.getBackendIndex(idx);
 
         final AttributeIndex index = new AttributeIndex(indexCfg, state, this);
-        index.open(txn);
+        index.open(txn, shouldCreate);
         if(!index.isTrusted())
         {
           logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, index.getName());
@@ -498,8 +501,7 @@
         BackendVLVIndexCfg vlvIndexCfg = config.getBackendVLVIndex(idx);
 
         VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this, txn);
-        vlvIndex.open(txn);
-
+        vlvIndex.open(txn, shouldCreate);
         if(!vlvIndex.isTrusted())
         {
           logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, vlvIndex.getName());
@@ -2664,7 +2666,7 @@
     {
       for(Tree tree : allTrees)
       {
-        tree.open(txn);
+        tree.open(txn, false);
       }
     }
     catch (Exception e)
@@ -2784,7 +2786,7 @@
     {
       for(Tree tree : allTrees)
       {
-        tree.open(txn);
+        tree.open(txn, true);
       }
 
       for (Tree tree : allTrees)
@@ -2830,7 +2832,7 @@
     }
     finally
     {
-      tree.open(txn);
+      tree.open(txn, true);
     }
     if(logger.isTraceEnabled())
     {
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
index 40c413d..a1cddad 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
@@ -231,6 +231,13 @@
     this.dataConfig = dataConfig;
   }
 
+  @Override
+  void open0(WriteableTransaction txn) throws StorageRuntimeException
+  {
+    // Make sure the tree is there and readable, even if the storage is READ_ONLY.
+    txn.getRecordCount(getName());
+  }
+
   /**
    * Decodes an entry from its tree representation.
    * <p>
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeBufferImporter.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeBufferImporter.java
index bebd929..452cf85 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeBufferImporter.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeBufferImporter.java
@@ -100,12 +100,12 @@
 import org.opends.server.backends.pdb.PDBStorage;
 import org.opends.server.backends.pluggable.AttributeIndex.MatchingRuleIndex;
 import org.opends.server.backends.pluggable.ImportLDIFReader.EntryInformation;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 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.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.UpdateFunction;
@@ -640,7 +640,7 @@
       {
         tempDN = baseDN.parent().child(tempDN);
       }
-      entryContainer = rootContainer.openEntryContainer(tempDN, txn);
+      entryContainer = rootContainer.openEntryContainer(tempDN, txn, AccessMode.READ_WRITE);
       break;
     case INCLUDE_EXCLUDE_BRANCHES:
       break;
@@ -3353,7 +3353,7 @@
           @Override
           public void run(WriteableTransaction txn) throws Exception
           {
-            txn.openTree(dnCache);
+            txn.openTree(dnCache, true);
           }
         });
       }
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeStorageImporter.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeStorageImporter.java
index 49c764b..78d7286 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeStorageImporter.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeStorageImporter.java
@@ -87,13 +87,13 @@
 import org.opends.server.backends.pluggable.AttributeIndex.MatchingRuleIndex;
 import org.opends.server.backends.pluggable.ImportLDIFReader.EntryInformation;
 import org.opends.server.backends.pluggable.OnDiskMergeBufferImporter.DNCache;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 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.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.SequentialCursor;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
 import org.opends.server.backends.pluggable.spi.StorageStatus;
 import org.opends.server.backends.pluggable.spi.TreeName;
@@ -1427,7 +1427,7 @@
       {
         tempDN = baseDN.parent().child(tempDN);
       }
-      entryContainer = rootContainer.openEntryContainer(tempDN, txn);
+      entryContainer = rootContainer.openEntryContainer(tempDN, txn, AccessMode.READ_WRITE);
       break;
     case INCLUDE_EXCLUDE_BRANCHES:
       break;
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/PersistentCompressedSchema.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/PersistentCompressedSchema.java
index 99fded9..d2fab73 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/PersistentCompressedSchema.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/PersistentCompressedSchema.java
@@ -38,6 +38,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
 import org.opends.server.api.CompressedSchema;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.Storage;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
@@ -84,6 +85,8 @@
    * @param storage
    *          A reference to the storage in which the trees will be held.
    * @param txn a non null transaction
+   * @param accessMode specifies how the storage has been opened (read only or read/write)
+   *
    * @throws StorageRuntimeException
    *           If a problem occurs while loading the compressed schema
    *           definitions from the tree.
@@ -91,11 +94,11 @@
    *           If an error occurs while loading and processing the compressed
    *           schema definitions.
    */
-  PersistentCompressedSchema(final Storage storage, WriteableTransaction txn)
+  PersistentCompressedSchema(final Storage storage, WriteableTransaction txn, AccessMode accessMode)
       throws StorageRuntimeException, InitializationException
   {
     this.storage = storage;
-    load(txn);
+    load(txn, accessMode.isWriteable());
   }
 
   /** {@inheritDoc} */
@@ -147,19 +150,11 @@
   }
 
 
-
-  /**
-   * Loads the compressed schema information from the tree.
-   *
-   * @throws StorageRuntimeException
-   *           If an error occurs while loading the definitions from the tree.
-   * @throws InitializationException
-   *           If an error occurs while loading and processing the definitions.
-   */
-  private void load(WriteableTransaction txn) throws StorageRuntimeException, InitializationException
+  private void load(WriteableTransaction txn, boolean shouldCreate)
+      throws StorageRuntimeException, InitializationException
   {
-    txn.openTree(adTreeName);
-    txn.openTree(ocTreeName);
+    txn.openTree(adTreeName, shouldCreate);
+    txn.openTree(ocTreeName, shouldCreate);
 
     // Cursor through the object class database and load the object class set
     // definitions. At the same time, figure out the highest token value and
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
index 57774bb..8e3df33 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
@@ -46,10 +46,10 @@
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.PluggableBackendCfg;
 import org.opends.server.api.CompressedSchema;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
 import org.opends.server.backends.pluggable.spi.StorageStatus;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
@@ -123,12 +123,14 @@
   /**
    * Opens the root container.
    *
+   * @param accessMode specifies how the container has to be opened (read-write or read-only)
+   *
    * @throws StorageRuntimeException
    *           If an error occurs when opening the storage.
    * @throws ConfigException
    *           If an configuration error occurs while opening the storage.
    */
-  void open(AccessMode accessMode) throws StorageRuntimeException, ConfigException
+  void open(final AccessMode accessMode) throws StorageRuntimeException, ConfigException
   {
     try
     {
@@ -138,8 +140,8 @@
         @Override
         public void run(WriteableTransaction txn) throws Exception
         {
-          compressedSchema = new PersistentCompressedSchema(storage, txn);
-          openAndRegisterEntryContainers(txn, config.getBaseDN());
+          compressedSchema = new PersistentCompressedSchema(storage, txn, accessMode);
+          openAndRegisterEntryContainers(txn, config.getBaseDN(), accessMode);
         }
       });
     }
@@ -165,17 +167,18 @@
    *          The base DN of the entry container to open.
    * @param txn
    *          The transaction
+   * @param accessMode specifies how the container has to be opened (read-write or read-only)
    * @return The opened entry container.
    * @throws StorageRuntimeException
    *           If an error occurs while opening the entry container.
    * @throws ConfigException
    *           If an configuration error occurs while opening the entry container.
    */
-  EntryContainer openEntryContainer(DN baseDN, WriteableTransaction txn)
+  EntryContainer openEntryContainer(DN baseDN, WriteableTransaction txn, AccessMode accessMode)
       throws StorageRuntimeException, ConfigException
   {
     EntryContainer ec = new EntryContainer(baseDN, backendId, config, storage, this);
-    ec.open(txn);
+    ec.open(txn, accessMode);
     return ec;
   }
 
@@ -204,6 +207,8 @@
    *
    * @param baseDNs
    *          The base DNs of the entry containers to open.
+   * @param accessMode specifies how the containers have to be opened (read-write or read-only)
+   *
    * @throws StorageRuntimeException
    *           If an error occurs while opening the entry container.
    * @throws InitializationException
@@ -213,13 +218,13 @@
    *           If a configuration error occurs while opening the entry
    *           container.
    */
-  private void openAndRegisterEntryContainers(WriteableTransaction txn, Set<DN> baseDNs) throws StorageRuntimeException,
-      InitializationException, ConfigException
+  private void openAndRegisterEntryContainers(WriteableTransaction txn, Set<DN> baseDNs, AccessMode accessMode)
+      throws StorageRuntimeException, InitializationException, ConfigException
   {
     EntryID highestID = null;
     for (DN baseDN : baseDNs)
     {
-      EntryContainer ec = openEntryContainer(baseDN, txn);
+      EntryContainer ec = openEntryContainer(baseDN, txn, accessMode);
       EntryID id = ec.getHighestEntryID(txn);
       registerEntryContainer(baseDN, ec);
       if (highestID == null || id.compareTo(highestID) > 0)
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
index ec2a586..cdb7f71 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/TracedStorage.java
@@ -31,6 +31,7 @@
 import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.Importer;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
@@ -206,9 +207,9 @@
     }
 
     @Override
-    public void openTree(final TreeName name)
+    public void openTree(final TreeName name, boolean createOnDemand)
     {
-      txn.openTree(name);
+      txn.openTree(name, createOnDemand);
       logger.trace("Storage@%s.WriteableTransaction@%s.openTree(%s, %s)",
           storageId(), id(), backendId, name);
     }
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Tree.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Tree.java
index b08bfa8..8671489 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Tree.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/Tree.java
@@ -38,15 +38,16 @@
 interface Tree
 {
   /**
-   * Opens a tree. If the provided configuration is transactional,
+   * Opens a tree, optionally creating it. If the provided configuration is transactional,
    * a transaction will be created and used to perform the open.
    *
    * @param txn
    *          a non null transaction
+   * @param createOnDemand true if the tree should be created if it does not exist
    * @throws StorageRuntimeException
    *           if an error occurs while opening the index.
    */
-  void open(WriteableTransaction txn) throws StorageRuntimeException;
+  void open(WriteableTransaction txn, boolean createOnDemand) throws StorageRuntimeException;
 
   /**
    * Deletes this tree and all of its contents.
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
index e4f3b20..a8619ef 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/VerifyJob.java
@@ -168,7 +168,13 @@
       {
         verifyDN2ID = true;
         verifyID2ChildrenCount = true;
-        attrIndexList.addAll(entryContainer.getAttributeIndexes());
+        for (AttributeIndex index : entryContainer.getAttributeIndexes())
+        {
+          if (index.isTrusted())
+          {
+            attrIndexList.add(index);
+          }
+        }
       }
       else
       {
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/AccessMode.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/AccessMode.java
new file mode 100644
index 0000000..77faf93
--- /dev/null
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/AccessMode.java
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2015 ForgeRock AS
+ */
+package org.opends.server.backends.pluggable.spi;
+
+/** Defines access modes of a Storage. */
+public enum AccessMode {
+  /** Constant used to open the Storage in read-only mode; implies missing trees will be ignored. */
+  READ_ONLY(false),
+  /** Constant used to open the Storage in read-write mode; implies trees will be created if not already present. */
+  READ_WRITE(true);
+
+  private boolean readWrite;
+
+  AccessMode(boolean update)
+  {
+    this.readWrite = update;
+  }
+
+  /**
+   * Returns if the storage is being opened READ_WRITE.
+   *
+   * @return true if the storage is being opened READ_WRITE
+   */
+  public boolean isWriteable()
+  {
+    return readWrite;
+  }
+}
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
index d5d73ba..60833fd 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
@@ -41,14 +41,6 @@
 public interface Storage extends Closeable
 {
 
-  /** Defines access modes of a Storage. */
-  public enum AccessMode {
-    /** Constant used to open the Storage in read-only mode. */
-    READ_ONLY,
-    /** Constant used to open the Storage in read-write mode. */
-    READ_WRITE;
-  }
-
   /**
    * Starts the import operation.
    *
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/WriteableTransaction.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/WriteableTransaction.java
index c345ea6..60515c6 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/WriteableTransaction.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/WriteableTransaction.java
@@ -33,12 +33,13 @@
 public interface WriteableTransaction extends ReadableTransaction
 {
   /**
-   * Opens the tree identified by the provided name. The tree is created if it does not already exist.
+   * Opens the tree identified by the provided name.
    *
    * @param name
    *          the tree name
+   * @param createOnDemand true if the tree should be created if it does not exist
    */
-  void openTree(TreeName name);
+  void openTree(TreeName name, boolean createOnDemand);
 
   /**
    * Renames the tree from the old to the new name.
diff --git a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DN2IDTest.java b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DN2IDTest.java
index 1a91334..e598272 100644
--- a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DN2IDTest.java
+++ b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DN2IDTest.java
@@ -44,11 +44,11 @@
 import org.opends.server.admin.std.server.BackendIndexCfg;
 import org.opends.server.admin.std.server.PDBBackendCfg;
 import org.opends.server.backends.pdb.PDBStorage;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.SequentialCursor;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
diff --git a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
index 3b717a8..8d33509 100644
--- a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
+++ b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/DefaultIndexTest.java
@@ -45,6 +45,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.DirectoryServerTestCase;
 import org.opends.server.backends.pluggable.State.IndexFlag;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
@@ -65,7 +66,7 @@
   public void setUp() {
     txn = new DummyWriteableTransaction();
     index = newIndex("test", 5, EnumSet.of(TRUSTED, COMPACTED));;
-    index.open(txn);
+    index.open(txn, true);
   }
 
   @Test
@@ -253,7 +254,7 @@
     }
 
     @Override
-    public void openTree(TreeName name)
+    public void openTree(TreeName name, boolean createOnDemand)
     {
       storage.put(name, new TreeMap<ByteString, ByteString>());
     }
diff --git a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ID2CountTest.java b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ID2CountTest.java
index 2d60a78..fdfda71 100644
--- a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ID2CountTest.java
+++ b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/ID2CountTest.java
@@ -45,9 +45,9 @@
 import org.opends.server.admin.std.server.BackendIndexCfg;
 import org.opends.server.admin.std.server.PDBBackendCfg;
 import org.opends.server.backends.pdb.PDBStorage;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
diff --git a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
index 2897c9a..477d3df 100644
--- a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
+++ b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
@@ -59,11 +59,11 @@
 import org.opends.server.api.Backend.BackendOperation;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.backends.VerifyConfig;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;
diff --git a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
index 43df905..577ce2d 100644
--- a/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
+++ b/opendj-sdk/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/StateTest.java
@@ -41,9 +41,9 @@
 import org.opends.server.admin.std.server.PDBBackendCfg;
 import org.opends.server.backends.pdb.PDBStorage;
 import org.opends.server.backends.pluggable.State.IndexFlag;
+import org.opends.server.backends.pluggable.spi.AccessMode;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
-import org.opends.server.backends.pluggable.spi.Storage.AccessMode;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableTransaction;

--
Gitblit v1.10.0