From 77131174b396433451592ca82362a3534ce74c80 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 16 Dec 2014 14:49:33 +0000
Subject: [PATCH] OPENDJ-1602 (CR-5566) New pluggable storage based backend

---
 opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java |  307 +++++++++++++++++++++++++-------------------------
 1 files changed, 152 insertions(+), 155 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
index a9ebc68..35716bd 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
@@ -152,14 +152,19 @@
   {
     /** {@inheritDoc} */
     @Override
-    public boolean isConfigurationAddAcceptable(
-        LocalDBIndexCfg cfg,
-        List<LocalizableMessage> unacceptableReasons)
+    public boolean isConfigurationAddAcceptable(final LocalDBIndexCfg cfg, List<LocalizableMessage> unacceptableReasons)
     {
       try
       {
-        //Try creating all the indexes before confirming they are valid ones.
-        new AttributeIndex(cfg, EntryContainer.this);
+        storage.write(new WriteOperation()
+        {
+          @Override
+          public void run(WriteableStorage txn) throws Exception
+          {
+            //Try creating all the indexes before confirming they are valid ones.
+            new AttributeIndex(cfg, EntryContainer.this, txn);
+          }
+        });
         return true;
       }
       catch(Exception e)
@@ -171,31 +176,33 @@
 
     /** {@inheritDoc} */
     @Override
-    public ConfigChangeResult applyConfigurationAdd(LocalDBIndexCfg cfg)
+    public ConfigChangeResult applyConfigurationAdd(final LocalDBIndexCfg cfg)
     {
-      boolean adminActionRequired = false;
-      List<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
-
+      final ConfigChangeResult ccr = new ConfigChangeResult();
       try
       {
-        AttributeIndex index = new AttributeIndex(cfg, EntryContainer.this);
-        index.open();
-        if(!index.isTrusted())
+        storage.write(new WriteOperation()
         {
-          adminActionRequired = true;
-          messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
-              cfg.getAttribute().getNameOrOID()));
-        }
-        attrIndexMap.put(cfg.getAttribute(), index);
+          @Override
+          public void run(WriteableStorage txn) throws Exception
+          {
+            final AttributeIndex index = new AttributeIndex(cfg, EntryContainer.this, txn);
+            index.open(txn);
+            if (!index.isTrusted())
+            {
+              ccr.setAdminActionRequired(true);
+              ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getAttribute().getNameOrOID()));
+            }
+            attrIndexMap.put(cfg.getAttribute(), index);
+          }
+        });
       }
       catch(Exception e)
       {
-        messages.add(LocalizableMessage.raw(e.getLocalizedMessage()));
-        return new ConfigChangeResult(
-            DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages);
+        ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+        ccr.addMessage(LocalizableMessage.raw(e.getLocalizedMessage()));
       }
-
-      return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+      return ccr;
     }
 
     /** {@inheritDoc} */
@@ -308,38 +315,38 @@
 
     /** {@inheritDoc} */
     @Override
-    public ConfigChangeResult applyConfigurationAdd(LocalDBVLVIndexCfg cfg)
+    public ConfigChangeResult applyConfigurationAdd(final LocalDBVLVIndexCfg cfg)
     {
-      boolean adminActionRequired = false;
-      ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
-
+      final ConfigChangeResult ccr = new ConfigChangeResult();
       try
       {
-        VLVIndex vlvIndex = new VLVIndex(cfg, state, storage, EntryContainer.this);
-        vlvIndex.open();
-        if(!vlvIndex.isTrusted())
+        storage.write(new WriteOperation()
         {
-          adminActionRequired = true;
-          messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
-              cfg.getName()));
-        }
-        vlvIndexMap.put(cfg.getName().toLowerCase(), vlvIndex);
+          @Override
+          public void run(WriteableStorage txn) throws Exception
+          {
+            VLVIndex vlvIndex = new VLVIndex(cfg, state, storage, EntryContainer.this, txn);
+            vlvIndex.open(txn);
+            if(!vlvIndex.isTrusted())
+            {
+              ccr.setAdminActionRequired(true);
+              ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getName()));
+            }
+            vlvIndexMap.put(cfg.getName().toLowerCase(), vlvIndex);
+          }
+        });
       }
       catch(Exception e)
       {
-        messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e)));
-        return new ConfigChangeResult(
-            DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages);
+        ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+        ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e)));
       }
-
-      return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+      return ccr;
     }
 
     /** {@inheritDoc} */
     @Override
-    public boolean isConfigurationDeleteAcceptable(
-        LocalDBVLVIndexCfg cfg,
-        List<LocalizableMessage> unacceptableReasons)
+    public boolean isConfigurationDeleteAcceptable(LocalDBVLVIndexCfg cfg, List<LocalizableMessage> unacceptableReasons)
     {
       // TODO: validate more before returning true?
       return true;
@@ -425,8 +432,7 @@
    * @throws StorageRuntimeException If an error occurs in the JE database.
    * @throws ConfigException if a configuration related error occurs.
    */
-  public void open()
-  throws StorageRuntimeException, ConfigException
+  public void open(WriteableStorage txn) throws StorageRuntimeException, ConfigException
   {
     try
     {
@@ -437,17 +443,17 @@
 
       id2entry = new ID2Entry(databasePrefix.child(ID2ENTRY_DATABASE_NAME),
           entryDataConfig, storage, this);
-      id2entry.open();
+      id2entry.open(txn);
 
       dn2id = new DN2ID(databasePrefix.child(DN2ID_DATABASE_NAME), storage, this);
-      dn2id.open();
+      dn2id.open(txn);
 
       state = new State(databasePrefix.child(STATE_DATABASE_NAME), storage, this);
-      state.open();
+      state.open(txn);
 
       if (config.isSubordinateIndexesEnabled())
       {
-        openSubordinateIndexes();
+        openSubordinateIndexes(txn);
       }
       else
       {
@@ -459,7 +465,7 @@
         {
           state.putIndexTrustState(null, id2children, false);
         }
-        id2children.open(); // No-op
+        id2children.open(txn); // No-op
 
         id2subtree = new NullIndex(databasePrefix.child(ID2SUBTREE_DATABASE_NAME),
             new ID2SIndexer(), state, storage, this);
@@ -467,20 +473,20 @@
         {
           state.putIndexTrustState(null, id2subtree, false);
         }
-        id2subtree.open(); // No-op
+        id2subtree.open(txn); // No-op
 
         logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backend.getBackendID());
       }
 
       dn2uri = new DN2URI(databasePrefix.child(REFERRAL_DATABASE_NAME), storage, this);
-      dn2uri.open();
+      dn2uri.open(txn);
 
       for (String idx : config.listLocalDBIndexes())
       {
         LocalDBIndexCfg indexCfg = config.getLocalDBIndex(idx);
 
-        AttributeIndex index = new AttributeIndex(indexCfg, this);
-        index.open();
+        AttributeIndex index = new AttributeIndex(indexCfg, this, txn);
+        index.open(txn);
         if(!index.isTrusted())
         {
           logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, index.getName());
@@ -492,8 +498,8 @@
       {
         LocalDBVLVIndexCfg vlvIndexCfg = config.getLocalDBVLVIndex(idx);
 
-        VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this);
-        vlvIndex.open();
+        VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this, txn);
+        vlvIndex.open(txn);
 
         if(!vlvIndex.isTrusted())
         {
@@ -683,9 +689,9 @@
    * @return The highest entry ID.
    * @throws StorageRuntimeException If an error occurs in the JE database.
    */
-  public EntryID getHighestEntryID() throws StorageRuntimeException
+  public EntryID getHighestEntryID(ReadableStorage txn) throws StorageRuntimeException
   {
-    Cursor cursor = storage.openCursor(id2entry.getName());
+    Cursor cursor = txn.openCursor(id2entry.getName());
     try
     {
       // Position a cursor on the last data item, and the key should give the highest ID.
@@ -821,9 +827,7 @@
           // Handle base-object search first.
           if (searchScope == SearchScope.BASE_OBJECT)
           {
-            // Fetch the base entry.
-            Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope);
-
+            final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope);
             if (!isManageDsaITOperation(searchOperation))
             {
               dn2uri.checkTargetForReferral(baseEntry, searchOperation.getScope());
@@ -1002,7 +1006,7 @@
             {
               rootContainer.getMonitorProvider().updateIndexedSearchCount();
             }
-            searchIndexed(entryIDList, candidatesAreInScope, searchOperation, pageRequest);
+            searchIndexed(txn, entryIDList, candidatesAreInScope, searchOperation, pageRequest);
           }
           else
           {
@@ -1045,7 +1049,7 @@
               }
             }
 
-            searchNotIndexed(searchOperation, pageRequest);
+            searchNotIndexed(txn, searchOperation, pageRequest);
           }
           return null;
         }
@@ -1075,7 +1079,7 @@
    * @throws DirectoryException If an error prevented the search from being
    * processed.
    */
-  private void searchNotIndexed(SearchOperation searchOperation, PagedResultsControl pageRequest)
+  private void searchNotIndexed(ReadableStorage txn, SearchOperation searchOperation, PagedResultsControl pageRequest)
       throws DirectoryException, CanceledOperationException
   {
     DN aBaseDN = searchOperation.getBaseDN();
@@ -1087,9 +1091,7 @@
     // the base entry processing if the cookie is set.
     if (pageRequest == null || pageRequest.getCookie().length() == 0)
     {
-      // Fetch the base entry.
-      Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope);
-
+      final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope);
       if (!manageDsaIT)
       {
         dn2uri.checkTargetForReferral(baseEntry, searchScope);
@@ -1105,7 +1107,7 @@
       }
 
       if (!manageDsaIT
-          && !dn2uri.returnSearchReferences(searchOperation)
+          && !dn2uri.returnSearchReferences(txn, searchOperation)
           && pageRequest != null)
       {
         // Indicate no more pages.
@@ -1165,7 +1167,7 @@
 
     try
     {
-      Cursor cursor = storage.openCursor(dn2id.getName());
+      final Cursor cursor = txn.openCursor(dn2id.getName());
       try
       {
         // Initialize the cursor very close to the starting value.
@@ -1305,11 +1307,9 @@
    * @throws DirectoryException If an error prevented the search from being
    * processed.
    */
-  private void searchIndexed(EntryIDSet entryIDList,
-      boolean candidatesAreInScope,
-      SearchOperation searchOperation,
-      PagedResultsControl pageRequest)
-  throws DirectoryException, CanceledOperationException
+  private void searchIndexed(ReadableStorage txn, EntryIDSet entryIDList, boolean candidatesAreInScope,
+      SearchOperation searchOperation, PagedResultsControl pageRequest) throws DirectoryException,
+      CanceledOperationException
   {
     SearchScope searchScope = searchOperation.getScope();
     DN aBaseDN = searchOperation.getBaseDN();
@@ -1336,8 +1336,7 @@
     }
     else if (!manageDsaIT)
     {
-      // Return any search result references.
-      continueSearch = dn2uri.returnSearchReferences(searchOperation);
+      continueSearch = dn2uri.returnSearchReferences(txn, searchOperation);
     }
 
     // Make sure the candidate list is smaller than the lookthrough limit
@@ -1408,9 +1407,7 @@
     if (searchOperation.getEntriesSent() == 0
         && searchOperation.getReferencesSent() == 0)
     {
-      // Fetch the base entry if it exists.
-      Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope);
-
+      final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope);
       if (!manageDsaIT)
       {
         dn2uri.checkTargetForReferral(baseEntry, searchScope);
@@ -1499,7 +1496,7 @@
             if (parentDN != null)
             {
               // Check for referral entries above the target.
-              dn2uri.targetEntryReferrals(entry.getName(), null);
+              dn2uri.targetEntryReferrals(txn, entry.getName(), null);
 
               // Read the parent ID from dn2id.
               parentID = dn2id.get(txn, parentDN, false);
@@ -1651,7 +1648,7 @@
           try
           {
             // Check for referral entries above the target entry.
-            dn2uri.targetEntryReferrals(entryDN, null);
+            dn2uri.targetEntryReferrals(txn, entryDN, null);
 
             // Determine whether this is a subtree delete.
             boolean isSubtreeDelete =
@@ -1677,8 +1674,6 @@
 
             ByteSequence startKey = suffix;
 
-            CursorConfig cursorConfig = new CursorConfig();
-            cursorConfig.setReadCommitted(true);
             Cursor cursor = dn2id.openCursor(txn);
             try
             {
@@ -1989,7 +1984,7 @@
             {
               // The entryDN does not exist.
               // Check for referral entries above the target entry.
-              dn2uri.targetEntryReferrals(entryDN, null);
+              dn2uri.targetEntryReferrals(txn, entryDN, null);
               return null;
             }
 
@@ -2212,7 +2207,7 @@
             if (oldApexID == null)
             {
               // Check for referral entries above the target entry.
-              dn2uri.targetEntryReferrals(currentDN, null);
+              dn2uri.targetEntryReferrals(txn, currentDN, null);
 
               LocalizableMessage message = ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN);
               DN matchedDN = getMatchedDN(baseDN);
@@ -3109,7 +3104,7 @@
         {
           TreeName oldName = db.getName();
           String newName = oldName.replace(databasePrefix, newDbPrefix);
-          storage.renameDatabase(null, oldName, newName);
+          storage.renameDatabase(txn, oldName, newName);
           db.setName(newName);
         }
 
@@ -3122,7 +3117,7 @@
       // Open the containers backup.
       for(DatabaseContainer db : databases)
       {
-        db.open();
+        db.open(txn);
       }
     }
   }
@@ -3161,74 +3156,79 @@
 
   /** {@inheritDoc} */
   @Override
-  public ConfigChangeResult applyConfigurationChange(LocalDBBackendCfg cfg)
+  public ConfigChangeResult applyConfigurationChange(final LocalDBBackendCfg cfg)
   {
-    boolean adminActionRequired = false;
-    ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
+    final ConfigChangeResult ccr = new ConfigChangeResult();
 
     exclusiveLock.lock();
     try
     {
-      if (config.isSubordinateIndexesEnabled() != cfg.isSubordinateIndexesEnabled())
+      storage.write(new WriteOperation()
       {
-        if (cfg.isSubordinateIndexesEnabled())
+        @Override
+        public void run(WriteableStorage txn) throws Exception
         {
-          // Re-enabling subordinate indexes.
-          openSubordinateIndexes();
+          if (config.isSubordinateIndexesEnabled() != cfg.isSubordinateIndexesEnabled())
+          {
+            if (cfg.isSubordinateIndexesEnabled())
+            {
+              // Re-enabling subordinate indexes.
+              openSubordinateIndexes(txn);
+            }
+            else
+            {
+              // Disabling subordinate indexes. Use a null index and ensure that
+              // future attempts to use the real indexes will fail.
+              id2children.close();
+              id2children = new NullIndex(databasePrefix.child(ID2CHILDREN_DATABASE_NAME),
+                  new ID2CIndexer(), state, storage, EntryContainer.this);
+              state.putIndexTrustState(null, id2children, false);
+              id2children.open(txn); // No-op
+
+              id2subtree.close();
+              id2subtree = new NullIndex(databasePrefix.child(ID2SUBTREE_DATABASE_NAME),
+                  new ID2SIndexer(), state, storage, EntryContainer.this);
+              state.putIndexTrustState(null, id2subtree, false);
+              id2subtree.open(txn); // No-op
+
+              logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, cfg.getBackendId());
+            }
+          }
+
+          if (config.getIndexEntryLimit() != cfg.getIndexEntryLimit())
+          {
+            if (id2children.setIndexEntryLimit(cfg.getIndexEntryLimit()))
+            {
+              ccr.setAdminActionRequired(true);
+              ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2children.getName()));
+            }
+
+            if (id2subtree.setIndexEntryLimit(cfg.getIndexEntryLimit()))
+            {
+              ccr.setAdminActionRequired(true);
+              ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2subtree.getName()));
+            }
+          }
+
+          DataConfig entryDataConfig = new DataConfig(cfg.isEntriesCompressed(),
+              cfg.isCompactEncoding(), rootContainer.getCompressedSchema());
+          id2entry.setDataConfig(entryDataConfig);
+
+          EntryContainer.this.config = cfg;
         }
-        else
-        {
-          // Disabling subordinate indexes. Use a null index and ensure that
-          // future attempts to use the real indexes will fail.
-          id2children.close();
-          id2children = new NullIndex(databasePrefix.child(ID2CHILDREN_DATABASE_NAME),
-              new ID2CIndexer(), state, storage, this);
-          state.putIndexTrustState(null, id2children, false);
-          id2children.open(); // No-op
-
-          id2subtree.close();
-          id2subtree = new NullIndex(databasePrefix.child(ID2SUBTREE_DATABASE_NAME),
-              new ID2SIndexer(), state, storage, this);
-          state.putIndexTrustState(null, id2subtree, false);
-          id2subtree.open(); // No-op
-
-          logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, cfg.getBackendId());
-        }
-      }
-
-      if (config.getIndexEntryLimit() != cfg.getIndexEntryLimit())
-      {
-        if (id2children.setIndexEntryLimit(cfg.getIndexEntryLimit()))
-        {
-          adminActionRequired = true;
-          messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2children.getName()));
-        }
-
-        if (id2subtree.setIndexEntryLimit(cfg.getIndexEntryLimit()))
-        {
-          adminActionRequired = true;
-          messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2subtree.getName()));
-        }
-      }
-
-      DataConfig entryDataConfig = new DataConfig(cfg.isEntriesCompressed(),
-          cfg.isCompactEncoding(), rootContainer.getCompressedSchema());
-      id2entry.setDataConfig(entryDataConfig);
-
-      this.config = cfg;
+      });
     }
-    catch (StorageRuntimeException e)
+    catch (Exception e)
     {
-      messages.add(LocalizableMessage.raw(stackTraceToSingleLineString(e)));
-      return new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
-          false, messages);
+      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+      ccr.addMessage(LocalizableMessage.raw(stackTraceToSingleLineString(e)));
     }
     finally
     {
       exclusiveLock.unlock();
     }
 
-    return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+    return ccr;
   }
 
   /**
@@ -3294,7 +3294,7 @@
     {
       for(DatabaseContainer db : databases)
       {
-        db.open();
+        db.open(txn);
       }
 
       Transaction txn = null;
@@ -3370,7 +3370,7 @@
     }
     finally
     {
-      database.open();
+      database.open(txn);
     }
     if(logger.isTraceEnabled())
     {
@@ -3401,20 +3401,18 @@
     return null;
   }
 
-  /**
-   * Opens the id2children and id2subtree indexes.
-   */
-  private void openSubordinateIndexes()
+  /** Opens the id2children and id2subtree indexes. */
+  private void openSubordinateIndexes(WriteableStorage txn)
   {
-    id2children = newIndex(ID2CHILDREN_DATABASE_NAME, new ID2CIndexer());
-    id2subtree = newIndex(ID2SUBTREE_DATABASE_NAME, new ID2SIndexer());
+    id2children = newIndex(txn, ID2CHILDREN_DATABASE_NAME, new ID2CIndexer());
+    id2subtree = newIndex(txn, ID2SUBTREE_DATABASE_NAME, new ID2SIndexer());
   }
 
-  private Index newIndex(String name, Indexer indexer)
+  private Index newIndex(WriteableStorage txn, String name, Indexer indexer)
   {
     final Index index = new Index(databasePrefix.child(name),
-        indexer, state, config.getIndexEntryLimit(), 0, true, storage, this);
-    index.open();
+        indexer, state, config.getIndexEntryLimit(), 0, true, storage, txn, this);
+    index.open(txn);
     if (!index.isTrusted())
     {
       logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, index.getName());
@@ -3430,10 +3428,10 @@
    * @param indexEntryLimit the index entry limit
    * @return a new index
    */
-  Index newIndexForAttribute(TreeName indexName, Indexer indexer, int indexEntryLimit)
+  Index newIndexForAttribute(WriteableStorage txn, TreeName indexName, Indexer indexer, int indexEntryLimit)
   {
     final int cursorEntryLimit = 100000;
-    return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, storage, this);
+    return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, storage, txn, this);
   }
 
 
@@ -3481,10 +3479,9 @@
    * @return the Entry matching the baseDN.
    * @throws DirectoryException if the baseDN doesn't exist.
    */
-  private Entry fetchBaseEntry(DN baseDN, SearchScope searchScope)
-          throws DirectoryException
+  private Entry fetchBaseEntry(ReadableStorage txn, DN baseDN, SearchScope searchScope)
+      throws DirectoryException
   {
-    // Fetch the base entry.
     Entry baseEntry = null;
     try
     {
@@ -3499,7 +3496,7 @@
     if (baseEntry == null)
     {
       // Check for referral entries above the base entry.
-      dn2uri.targetEntryReferrals(baseDN, searchScope);
+      dn2uri.targetEntryReferrals(txn, baseDN, searchScope);
 
       LocalizableMessage message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN);
       DN matchedDN = getMatchedDN(baseDN);

--
Gitblit v1.10.0