From 4640fec656d96f3891a5534948f0b4c81df2f89d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 26 Jan 2012 23:53:08 +0000
Subject: [PATCH] Fix OPENDJ-406:  Add support for rebuilding all degraded indexes to rebuild-index tool

---
 opends/src/server/org/opends/server/tasks/RebuildTask.java                                   |   25 +
 opends/src/server/org/opends/server/backends/jeb/RebuildConfig.java                          |   39 +++
 opends/src/messages/messages/tools.properties                                                |   11 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java |   24 ++
 opends/src/messages/messages/task.properties                                                 |    3 
 opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java                    |  377 ++++++++++++++++++++++---------------
 opends/src/server/org/opends/server/tools/RebuildIndex.java                                  |   63 +++++
 opends/src/messages/messages/jeb.properties                                                  |    3 
 opends/src/server/org/opends/server/config/ConfigConstants.java                              |    7 
 9 files changed, 370 insertions(+), 182 deletions(-)

diff --git a/opends/src/messages/messages/jeb.properties b/opends/src/messages/messages/jeb.properties
index 93c8282..fa9c435 100644
--- a/opends/src/messages/messages/jeb.properties
+++ b/opends/src/messages/messages/jeb.properties
@@ -21,6 +21,7 @@
 # CDDL HEADER END
 #
 #      Copyright 2006-2010 Sun Microsystems, Inc.
+#      Portions copyright 2012 ForgeRock AS.
 
 
 
@@ -448,4 +449,6 @@
   disabled for the extensible index of the %s attribute
 NOTICE_JEB_SUBORDINATE_INDEXES_DISABLED_230=The subordinate indexes have been \
  disabled for database backend %s
+NOTICE_JEB_REBUILD_DEGRADED_START_231=Rebuild of all degraded indexes started \
+ with %d total entries to process
 
diff --git a/opends/src/messages/messages/task.properties b/opends/src/messages/messages/task.properties
index 6abd5eb..22570f1 100644
--- a/opends/src/messages/messages/task.properties
+++ b/opends/src/messages/messages/task.properties
@@ -21,6 +21,7 @@
 # CDDL HEADER END
 #
 #      Copyright 2006-2009 Sun Microsystems, Inc.
+#      Portions copyright 2012 ForgeRock AS.
 
 
 
@@ -197,7 +198,7 @@
  server at %s on port %s. Check this port is an administration port
 INFO_TASK_STATE_RECURRING_107=Recurring
 SEVERE_ERR_TASK_INDEXREBUILD_ALL_ERROR_108=Index option cannot be specified when \
-the rebuildAll option is used
+the rebuildAll or rebuildDegraded option is used
 INFO_TASK_PURGE_CONFLICTS_HIST_NAME_109=Purge conflicts historical
 SEVERE_ERR_TASK_INVALID_ATTRIBUTE_VALUE_110=Attribute %s has an invalid value. \
 Reason: %s
\ No newline at end of file
diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index 235cfbd..51a6fd3 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -21,7 +21,7 @@
 # CDDL HEADER END
 #
 #      Copyright 2006-2010 Sun Microsystems, Inc.
-#      Portions Copyright 2011 ForgeRock AS
+#      Portions Copyright 2011-2012 ForgeRock AS
 
 
 
@@ -2537,7 +2537,7 @@
 SEVERE_ERR_ENCPW_CANNOT_READ_PW_1694=Cannot read password from the input: %s
 INFO_REBUILDINDEX_DESCRIPTION_REBUILD_ALL_1695=Rebuild all indexes, including \
 any DN2ID, DN2URI, VLV and extensible indexes. Cannot be used \
-with the "-i" option
+with the "-i" option or the "--rebuildDegraded" option
 INFO_REBUILDINDEX_TEMP_DIR_PLACEHOLDER_1697={directory}
 INFO_REBUILDINDEX_DESCRIPTION_TEMP_DIRECTORY_1698=Path to temporary directory \
 for index scratch files during index rebuilding
@@ -2586,3 +2586,10 @@
  has an invalid format.  The schedule must be expressed using a crontab(5) \
  format.  Error details: %s
 INFO_DESCRIPTION_REMOTE_1719=Connect to a remote server
+INFO_REBUILDINDEX_DESCRIPTION_REBUILD_DEGRADED_1720=Rebuild all degraded \
+ indexes, including any DN2ID, DN2URI, VLV and extensible indexes. Cannot be used \
+ with the "-i" option or the "--rebuildAll" option
+SEVERE_ERR_REBUILDINDEX_REBUILD_DEGRADED_ERROR_1721=Index "-i" option cannot be \
+ specified with the "--rebuildDegraded" option
+SEVERE_ERR_REBUILDINDEX_REBUILD_ALL_DEGRADED_ERROR_1722=Option "--rebuildAll" \
+ cannot be specified with the "--rebuildDegraded" option
diff --git a/opends/src/server/org/opends/server/backends/jeb/RebuildConfig.java b/opends/src/server/org/opends/server/backends/jeb/RebuildConfig.java
index 0c6f332..9910e05 100644
--- a/opends/src/server/org/opends/server/backends/jeb/RebuildConfig.java
+++ b/opends/src/server/org/opends/server/backends/jeb/RebuildConfig.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions copyright 2012 ForgeRock AS.
  */
 package org.opends.server.backends.jeb;
 
@@ -36,6 +37,26 @@
 public class RebuildConfig
 {
   /**
+   * Identifies how indexes will be selected for rebuild.
+   */
+  public static enum RebuildMode {
+    /**
+     * Rebuild all indexes, including system indexes.
+     */
+    ALL,
+
+    /**
+     * Rebuild all degraded indexes, including system indexes.
+     */
+    DEGRADED,
+
+    /**
+     * Rebuild used defined list of indexes.
+     */
+    USER_DEFINED;
+  }
+
+  /**
    * The base DN to rebuild.
    */
   private DN baseDN;
@@ -45,7 +66,7 @@
    */
   private ArrayList<String> rebuildList;
 
-  private boolean rebuildAll = false;
+  private RebuildMode rebuildMode = RebuildMode.USER_DEFINED;
 
   private String tmpDirectory;
 
@@ -219,23 +240,23 @@
 
 
   /**
-   * Set the rebuild all boolean to the specified value.
+   * Sets the rebuild mode.
    *
-   * @param v The value to set the rebuild all boolean to.
+   * @param mode The new rebuild mode.
    */
-  public void setRebuildAll(boolean v)
+  public void setRebuildMode(RebuildMode mode)
   {
-    rebuildAll = v;
+    rebuildMode = mode;
   }
 
   /**
-   * Return the rebuild all boolean value.
+   * Returns the rebuild mode.
    *
-   * @return Return the rebuild all boolean value.
+   * @return The rebuild mode.
    */
-  public boolean isRebuildAll()
+  public RebuildMode getRebuildMode()
   {
-    return rebuildAll;
+    return rebuildMode;
   }
 
 
diff --git a/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java b/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
index cbe9473..4a02da5 100644
--- a/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/importLDIF/Importer.java
@@ -315,22 +315,7 @@
     }
 
     // Determine the number of indexes.
-    int indexes = 2; // dn2id + dn2uri
-    for (String indexName : localDBBackendCfg.listLocalDBIndexes())
-    {
-      LocalDBIndexCfg index = localDBBackendCfg.getLocalDBIndex(indexName);
-      SortedSet<IndexType> types = index.getIndexType();
-      if (types.contains(IndexType.EXTENSIBLE))
-      {
-        indexes += types.size() - 1
-            + index.getIndexExtensibleMatchingRule().size();
-      }
-      else
-      {
-        indexes += types.size();
-      }
-    }
-    this.indexCount = indexes;
+    this.indexCount = getTotalIndexCount(localDBBackendCfg);
 
     if (!importConfiguration.appendToExistingData())
     {
@@ -378,6 +363,29 @@
 
 
 
+  private int getTotalIndexCount(LocalDBBackendCfg localDBBackendCfg)
+      throws ConfigException
+  {
+    int indexes = 2; // dn2id, dn2uri
+    for (String indexName : localDBBackendCfg.listLocalDBIndexes())
+    {
+      LocalDBIndexCfg index = localDBBackendCfg.getLocalDBIndex(indexName);
+      SortedSet<IndexType> types = index.getIndexType();
+      if (types.contains(IndexType.EXTENSIBLE))
+      {
+        indexes += types.size() - 1
+            + index.getIndexExtensibleMatchingRule().size();
+      }
+      else
+      {
+        indexes += types.size();
+      }
+    }
+    return indexes;
+  }
+
+
+
   /**
    * Return the suffix instance in the specified map that matches the specified
    * DN.
@@ -3229,9 +3237,6 @@
    //The suffix instance.
    private Suffix suffix = null;
 
-   //Set to true if the rebuild all flag was specified.
-   private final boolean rebuildAll;
-
    //The entry container.
    private EntryContainer entryContainer;
 
@@ -3248,7 +3253,6 @@
     {
       this.rebuildConfig = rebuildConfig;
       this.cfg = cfg;
-      rebuildAll = rebuildConfig.isRebuildAll();
     }
 
 
@@ -3290,9 +3294,18 @@
         sb.append(index);
       }
       totalEntries = suffix.getID2Entry().getRecordCount();
-      Message message = NOTE_JEB_REBUILD_START.get(sb.toString(), totalEntries);
-      if(rebuildAll) {
+
+      Message message;
+      switch (rebuildConfig.getRebuildMode()) {
+      case ALL:
         message = NOTE_JEB_REBUILD_ALL_START.get(totalEntries);
+        break;
+      case DEGRADED:
+        message = NOTE_JEB_REBUILD_DEGRADED_START.get(totalEntries);
+        break;
+      default:
+        message = NOTE_JEB_REBUILD_START.get(sb.toString(), totalEntries);
+        break;
       }
       logError(message);
     }
@@ -3380,27 +3393,35 @@
         DatabaseException, InterruptedException, ExecutionException,
         JebException
     {
-      if (rebuildAll)
+      switch (rebuildConfig.getRebuildMode())
       {
+      case ALL:
         setAllIndexesTrusted(false);
-      }
-      else
-      {
+        break;
+      case DEGRADED:
+        // Nothing to do: degraded indexes are already untrusted.
+        break;
+      default:
         setRebuildListIndexesTrusted(false);
+        break;
       }
+
       phaseOne();
       if (isCanceled)
       {
         throw new InterruptedException("Rebuild Index canceled.");
       }
       phaseTwo();
-      if (rebuildAll)
+
+      switch (rebuildConfig.getRebuildMode())
       {
+      case ALL:
+      case DEGRADED:
         setAllIndexesTrusted(true);
-      }
-      else
-      {
+        break;
+      default:
         setRebuildListIndexesTrusted(true);
+        break;
       }
     }
 
@@ -3467,14 +3488,19 @@
 
     private void phaseOne() throws DatabaseException,
             InterruptedException, ExecutionException {
-      if(rebuildAll)
+      switch (rebuildConfig.getRebuildMode())
       {
-        clearAllIndexes();
-      }
-      else
-      {
+      case ALL:
+        clearAllIndexes(false);
+        break;
+      case DEGRADED:
+        clearAllIndexes(true);
+        break;
+      default:
         clearRebuildListIndexes();
+        break;
       }
+
       initializeIndexBuffers();
       RebuildFirstPhaseProgressTask progressTask =
               new RebuildFirstPhaseProgressTask();
@@ -3536,26 +3562,18 @@
 
     private int getIndexCount() throws ConfigException, JebException
     {
-      int indexCount;
-      if(!rebuildAll)
+      switch (rebuildConfig.getRebuildMode())
       {
-        indexCount = getRebuildListIndexCount(cfg);
+      case ALL:
+        return getTotalIndexCount(cfg);
+      case DEGRADED:
+        // FIXME: since the environment is not started we cannot determine which
+        // indexes are degraded. As a workaround, be conservative and assume all
+        // indexes need rebuilding.
+        return getTotalIndexCount(cfg);
+      default:
+        return getRebuildListIndexCount(cfg);
       }
-      else
-      {
-        indexCount = getAllIndexesCount(cfg);
-      }
-      return indexCount;
-    }
-
-
-    private int getAllIndexesCount(LocalDBBackendCfg cfg)
-    {
-      int indexCount = cfg.listLocalDBIndexes().length;
-      indexCount += cfg.listLocalDBVLVIndexes().length;
-      //Add four for: DN, id2subtree, id2children and dn2uri.
-      indexCount += 4;
-      return indexCount;
     }
 
 
@@ -3744,15 +3762,17 @@
           String lowerName = index.toLowerCase();
           if (lowerName.equals("dn2id"))
           {
-            clearDN2IDIndexes();
+            clearDN2IDIndexes(false);
           }
           else if (lowerName.equals("dn2uri"))
           {
-            clearDN2URI();
+            clearDN2URI(false);
           }
           else if (lowerName.startsWith("vlv."))
           {
-            clearVLVIndex(lowerName.substring(4));
+            VLVIndex vlvIndex = entryContainer.getVLVIndex(lowerName
+                .substring(4));
+            clearVLVIndex(vlvIndex, false);
           }
           else
           {
@@ -3881,7 +3901,7 @@
             }
             else
             {
-              clearAttributeIndexes(attrIndex, attrType);
+              clearAttributeIndexes(attrIndex, attrType, false);
             }
           }
         }
@@ -3889,137 +3909,192 @@
     }
 
 
-    private void clearAllIndexes() throws DatabaseException
+    private void clearAllIndexes(boolean onlyDegraded) throws DatabaseException
     {
       for(Map.Entry<AttributeType, AttributeIndex> mapEntry :
               suffix.getAttrIndexMap().entrySet()) {
         AttributeType attributeType = mapEntry.getKey();
         AttributeIndex attributeIndex = mapEntry.getValue();
-        clearAttributeIndexes(attributeIndex, attributeType);
+        clearAttributeIndexes(attributeIndex, attributeType, onlyDegraded);
       }
       for(VLVIndex vlvIndex : suffix.getEntryContainer().getVLVIndexes()) {
-        entryContainer.clearDatabase(vlvIndex);
+        clearVLVIndex(vlvIndex, onlyDegraded);
       }
-      clearDN2IDIndexes();
+      clearDN2IDIndexes(onlyDegraded);
       if(entryContainer.getDN2URI() != null)
       {
-        clearDN2URI();
+        clearDN2URI(onlyDegraded);
       }
     }
 
 
-    private void clearVLVIndex(String name)
-            throws DatabaseException
+
+    private void clearVLVIndex(VLVIndex vlvIndex, boolean onlyDegraded)
+        throws DatabaseException
     {
-      VLVIndex vlvIndex = entryContainer.getVLVIndex(name);
-      entryContainer.clearDatabase(vlvIndex);
-      vlvIndexes.add(vlvIndex);
+      if (!onlyDegraded || !vlvIndex.isTrusted())
+      {
+        entryContainer.clearDatabase(vlvIndex);
+        vlvIndexes.add(vlvIndex);
+      }
     }
 
 
-    private void clearDN2URI() throws DatabaseException
+
+    private void clearDN2URI(boolean onlyDegraded) throws DatabaseException
     {
-      entryContainer.clearDatabase(entryContainer.getDN2URI());
-      dn2uri = entryContainer.getDN2URI();
+      if (!onlyDegraded)
+      {
+        // dn2uri does not have a trusted status.
+        entryContainer.clearDatabase(entryContainer.getDN2URI());
+        dn2uri = entryContainer.getDN2URI();
+      }
     }
 
 
-    private void clearDN2IDIndexes() throws DatabaseException
+
+    private void clearDN2IDIndexes(boolean onlyDegraded)
+        throws DatabaseException
     {
-      entryContainer.clearDatabase(entryContainer.getDN2ID());
-      entryContainer.clearDatabase(entryContainer.getID2Children());
-      entryContainer.clearDatabase(entryContainer.getID2Subtree());
-      dn2id = entryContainer.getDN2ID();
+      if (!onlyDegraded || !entryContainer.getID2Children().isTrusted()
+          || !entryContainer.getID2Subtree().isTrusted())
+      {
+        entryContainer.clearDatabase(entryContainer.getDN2ID());
+        entryContainer.clearDatabase(entryContainer.getID2Children());
+        entryContainer.clearDatabase(entryContainer.getID2Subtree());
+        dn2id = entryContainer.getDN2ID();
+      }
     }
 
 
     private void clearAttributeIndexes(AttributeIndex attrIndex,
-                                      AttributeType attrType)
+                                      AttributeType attrType,
+                                      boolean onlyDegraded)
             throws DatabaseException
     {
-      Index partialAttrIndex;
-      if(attrIndex.getSubstringIndex() != null)
+      if (attrIndex.getSubstringIndex() != null)
       {
-        partialAttrIndex = attrIndex.getSubstringIndex();
-        int id = System.identityHashCode(partialAttrIndex);
-        idContainerMap.putIfAbsent(id, partialAttrIndex);
-        entryContainer.clearDatabase(partialAttrIndex);
-        IndexKey indexKey =
-                new IndexKey(attrType, ImportIndexType.SUBSTRING,
-                        partialAttrIndex.getIndexEntryLimit());
-        indexMap.put(indexKey, partialAttrIndex);
+        Index partialAttrIndex = attrIndex.getSubstringIndex();
+        if (!onlyDegraded || !partialAttrIndex.isTrusted())
+        {
+          int id = System.identityHashCode(partialAttrIndex);
+          idContainerMap.putIfAbsent(id, partialAttrIndex);
+          entryContainer.clearDatabase(partialAttrIndex);
+          IndexKey indexKey = new IndexKey(attrType, ImportIndexType.SUBSTRING,
+              partialAttrIndex.getIndexEntryLimit());
+          indexMap.put(indexKey, partialAttrIndex);
+        }
       }
-      if(attrIndex.getOrderingIndex() != null)
+      if (attrIndex.getOrderingIndex() != null)
       {
-        partialAttrIndex = attrIndex.getOrderingIndex();
-        int id = System.identityHashCode(partialAttrIndex);
-        idContainerMap.putIfAbsent(id, partialAttrIndex);
-        entryContainer.clearDatabase(partialAttrIndex);
-        IndexKey indexKey =
-                new IndexKey(attrType, ImportIndexType.ORDERING,
-                        partialAttrIndex.getIndexEntryLimit());
-        indexMap.put(indexKey, partialAttrIndex);
+        Index partialAttrIndex = attrIndex.getOrderingIndex();
+        if (!onlyDegraded || !partialAttrIndex.isTrusted())
+        {
+          int id = System.identityHashCode(partialAttrIndex);
+          idContainerMap.putIfAbsent(id, partialAttrIndex);
+          entryContainer.clearDatabase(partialAttrIndex);
+          IndexKey indexKey = new IndexKey(attrType, ImportIndexType.ORDERING,
+              partialAttrIndex.getIndexEntryLimit());
+          indexMap.put(indexKey, partialAttrIndex);
+        }
       }
       if(attrIndex.getEqualityIndex() != null)
       {
-        partialAttrIndex = attrIndex.getEqualityIndex();
-        int id = System.identityHashCode(partialAttrIndex);
-        idContainerMap.putIfAbsent(id, partialAttrIndex);
-        entryContainer.clearDatabase(partialAttrIndex);
-        IndexKey indexKey =
-                new IndexKey(attrType, ImportIndexType.EQUALITY,
-                        partialAttrIndex.getIndexEntryLimit());
-        indexMap.put(indexKey, partialAttrIndex);
-      }
-      if(attrIndex.getPresenceIndex() != null)
-      {
-        partialAttrIndex = attrIndex.getPresenceIndex();
-        int id = System.identityHashCode(partialAttrIndex);
-        idContainerMap.putIfAbsent(id, partialAttrIndex);
-        entryContainer.clearDatabase(partialAttrIndex);
-        IndexKey indexKey =
-                new IndexKey(attrType, ImportIndexType.PRESENCE,
-                        partialAttrIndex.getIndexEntryLimit());
-        indexMap.put(indexKey, partialAttrIndex);
-
-      }
-      if(attrIndex.getApproximateIndex() != null)
-      {
-        partialAttrIndex = attrIndex.getApproximateIndex();
-        int id = System.identityHashCode(partialAttrIndex);
-        idContainerMap.putIfAbsent(id, partialAttrIndex);
-        entryContainer.clearDatabase(partialAttrIndex);
-        IndexKey indexKey =
-                new IndexKey(attrType, ImportIndexType.APPROXIMATE,
-                        partialAttrIndex.getIndexEntryLimit());
-        indexMap.put(indexKey, partialAttrIndex);
-      }
-      Map<String,Collection<Index>> extensibleMap =
-              attrIndex.getExtensibleIndexes();
-      if(!extensibleMap.isEmpty()) {
-        Collection<Index> subIndexes =
-                attrIndex.getExtensibleIndexes().get(
-                        EXTENSIBLE_INDEXER_ID_SUBSTRING);
-        if(subIndexes != null) {
-          for(Index subIndex : subIndexes) {
-            entryContainer.clearDatabase(subIndex);
-            int id = System.identityHashCode(subIndex);
-            idContainerMap.putIfAbsent(id, subIndex);
-          }
-          extensibleIndexMap.put(new IndexKey(attrType,
-                  ImportIndexType.EX_SUBSTRING, 0), subIndexes);
+        Index partialAttrIndex = attrIndex.getEqualityIndex();
+        if (!onlyDegraded || !partialAttrIndex.isTrusted())
+        {
+          int id = System.identityHashCode(partialAttrIndex);
+          idContainerMap.putIfAbsent(id, partialAttrIndex);
+          entryContainer.clearDatabase(partialAttrIndex);
+          IndexKey indexKey = new IndexKey(attrType, ImportIndexType.EQUALITY,
+              partialAttrIndex.getIndexEntryLimit());
+          indexMap.put(indexKey, partialAttrIndex);
         }
-        Collection<Index> sharedIndexes =
-                attrIndex.getExtensibleIndexes().
-                                             get(EXTENSIBLE_INDEXER_ID_SHARED);
-        if(sharedIndexes !=null) {
-          for(Index sharedIndex : sharedIndexes) {
-            entryContainer.clearDatabase(sharedIndex);
-            int id = System.identityHashCode(sharedIndex);
-            idContainerMap.putIfAbsent(id, sharedIndex);
+      }
+      if (attrIndex.getPresenceIndex() != null)
+      {
+        Index partialAttrIndex = attrIndex.getPresenceIndex();
+        if (!onlyDegraded || !partialAttrIndex.isTrusted())
+        {
+          int id = System.identityHashCode(partialAttrIndex);
+          idContainerMap.putIfAbsent(id, partialAttrIndex);
+          entryContainer.clearDatabase(partialAttrIndex);
+          IndexKey indexKey = new IndexKey(attrType, ImportIndexType.PRESENCE,
+              partialAttrIndex.getIndexEntryLimit());
+          indexMap.put(indexKey, partialAttrIndex);
+        }
+      }
+      if (attrIndex.getApproximateIndex() != null)
+      {
+        Index partialAttrIndex = attrIndex.getApproximateIndex();
+        if (!onlyDegraded || !partialAttrIndex.isTrusted())
+        {
+          int id = System.identityHashCode(partialAttrIndex);
+          idContainerMap.putIfAbsent(id, partialAttrIndex);
+          entryContainer.clearDatabase(partialAttrIndex);
+          IndexKey indexKey = new IndexKey(attrType,
+              ImportIndexType.APPROXIMATE,
+              partialAttrIndex.getIndexEntryLimit());
+          indexMap.put(indexKey, partialAttrIndex);
+        }
+      }
+      Map<String, Collection<Index>> extensibleMap = attrIndex
+          .getExtensibleIndexes();
+      if (!extensibleMap.isEmpty())
+      {
+        Collection<Index> subIndexes = attrIndex.getExtensibleIndexes().get(
+            EXTENSIBLE_INDEXER_ID_SUBSTRING);
+        if (subIndexes != null && !subIndexes.isEmpty())
+        {
+          List<Index> mutableCopy = new LinkedList<Index>(subIndexes);
+          Iterator<Index> i = mutableCopy.iterator();
+          while (i.hasNext())
+          {
+            Index subIndex = i.next();
+            if (!onlyDegraded || !subIndex.isTrusted())
+            {
+              entryContainer.clearDatabase(subIndex);
+              int id = System.identityHashCode(subIndex);
+              idContainerMap.putIfAbsent(id, subIndex);
+            }
+            else
+            {
+              // This index is not a candidate for rebuilding.
+              i.remove();
+            }
           }
-          extensibleIndexMap.put(new IndexKey(attrType,
-                  ImportIndexType.EX_SHARED, 0), sharedIndexes);
+          if (!mutableCopy.isEmpty())
+          {
+            extensibleIndexMap.put(new IndexKey(attrType,
+                ImportIndexType.EX_SUBSTRING, 0), mutableCopy);
+          }
+        }
+        Collection<Index> sharedIndexes = attrIndex.getExtensibleIndexes().get(
+            EXTENSIBLE_INDEXER_ID_SHARED);
+        if (sharedIndexes != null && !sharedIndexes.isEmpty())
+        {
+          List<Index> mutableCopy = new LinkedList<Index>(sharedIndexes);
+          Iterator<Index> i = mutableCopy.iterator();
+          while (i.hasNext())
+          {
+            Index sharedIndex = i.next();
+            if (!onlyDegraded || !sharedIndex.isTrusted())
+            {
+              entryContainer.clearDatabase(sharedIndex);
+              int id = System.identityHashCode(sharedIndex);
+              idContainerMap.putIfAbsent(id, sharedIndex);
+            }
+            else
+            {
+              // This index is not a candidate for rebuilding.
+              i.remove();
+            }
+          }
+          if (!mutableCopy.isEmpty())
+          {
+            extensibleIndexMap.put(new IndexKey(attrType,
+                ImportIndexType.EX_SHARED, 0), mutableCopy);
+          }
         }
       }
     }
diff --git a/opends/src/server/org/opends/server/config/ConfigConstants.java b/opends/src/server/org/opends/server/config/ConfigConstants.java
index 232f815..fef6d3f 100644
--- a/opends/src/server/org/opends/server/config/ConfigConstants.java
+++ b/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -23,7 +23,7 @@
  *
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
- *      Portions copyright 2011 ForgeRock AS
+ *      Portions copyright 2011-2012 ForgeRock AS
  */
 package org.opends.server.config;
 
@@ -4346,6 +4346,11 @@
   public static final String REBUILD_ALL = "rebuildall";
 
   /**
+   * Used to specify that the rebuild degraded boolean should be set.
+   */
+  public static final String REBUILD_DEGRADED = "rebuilddegraded";
+
+  /**
    * The name of the objectclass that will be used for a Directory Server
    * reset generationId task definition.
    */
diff --git a/opends/src/server/org/opends/server/tasks/RebuildTask.java b/opends/src/server/org/opends/server/tasks/RebuildTask.java
index e7a800b..f5fcba9 100644
--- a/opends/src/server/org/opends/server/tasks/RebuildTask.java
+++ b/opends/src/server/org/opends/server/tasks/RebuildTask.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions copyright 2012 ForgeRock AS.
  */
 package org.opends.server.tasks;
 import org.opends.messages.Message;
@@ -32,6 +33,7 @@
 import org.opends.server.backends.task.TaskState;
 import org.opends.server.backends.jeb.RebuildConfig;
 import org.opends.server.backends.jeb.BackendImpl;
+import org.opends.server.backends.jeb.RebuildConfig.RebuildMode;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
@@ -74,7 +76,7 @@
   String baseDN = null;
   ArrayList<String> indexes = null;
   private String tmpDirectory = null;
-  private boolean rebuildAll = false;
+  private RebuildMode rebuildMode = RebuildMode.USER_DEFINED;
 
   /**
    * {@inheritDoc}
@@ -125,14 +127,14 @@
     attrList = taskEntry.getAttribute(typeIndex);
     indexes = TaskUtils.getMultiValueString(attrList);
 
-    if(isRebuildAll(indexes))
+    rebuildMode = getRebuildMode(indexes);
+    if(rebuildMode != RebuildMode.USER_DEFINED)
     {
       if(indexes.size() != 1)
       {
         Message msg = ERR_TASK_INDEXREBUILD_ALL_ERROR.get();
         throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
       }
-      rebuildAll = true;
       indexes.clear();
     }
 
@@ -141,16 +143,21 @@
 
   }
 
-  private boolean isRebuildAll(List<String> indexList)
+  private RebuildMode getRebuildMode(List<String> indexList)
   {
-    for(String s : indexList)
+    for (String s : indexList)
     {
-      if(s.equalsIgnoreCase(REBUILD_ALL))
+      if (s.equalsIgnoreCase(REBUILD_ALL))
       {
-        return true;
+        return RebuildMode.ALL;
+      }
+
+      if (s.equalsIgnoreCase(REBUILD_DEGRADED))
+      {
+        return RebuildMode.DEGRADED;
       }
     }
-    return false;
+    return RebuildMode.USER_DEFINED;
   }
 
   /**
@@ -240,7 +247,7 @@
       tmpDirectory = "import-tmp";
     }
     rebuildConfig.setTmpDirectory(tmpDirectory);
-    rebuildConfig.setRebuildAll(rebuildAll);
+    rebuildConfig.setRebuildMode(rebuildMode);
     TaskState returnCode = TaskState.COMPLETED_SUCCESSFULLY;
     // Launch the rebuild process.
     try
diff --git a/opends/src/server/org/opends/server/tools/RebuildIndex.java b/opends/src/server/org/opends/server/tools/RebuildIndex.java
index c26b30f..b5804ff 100644
--- a/opends/src/server/org/opends/server/tools/RebuildIndex.java
+++ b/opends/src/server/org/opends/server/tools/RebuildIndex.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions copyright 2012 ForgeRock AS.
  */
 package org.opends.server.tools;
 import org.opends.messages.Message;
@@ -60,6 +61,7 @@
 import org.opends.server.api.DebugLogPublisher;
 import org.opends.server.backends.jeb.BackendImpl;
 import org.opends.server.backends.jeb.RebuildConfig;
+import org.opends.server.backends.jeb.RebuildConfig.RebuildMode;
 import org.opends.server.admin.std.server.BackendCfg;
 
 import java.io.OutputStream;
@@ -81,7 +83,8 @@
   private StringArgument  baseDNString            = null;
   private StringArgument  indexList               = null;
   private StringArgument  tmpDirectory            = null;
-  private BooleanArgument rebuildAll               = null;
+  private BooleanArgument rebuildAll              = null;
+  private BooleanArgument rebuildDegraded         = null;
 
   /**
    * Processes the command-line arguments and invokes the rebuild process.
@@ -195,6 +198,12 @@
       argParser.addArgument(rebuildAll);
 
 
+      rebuildDegraded =
+           new BooleanArgument("rebuildDegraded", null, "rebuildDegraded",
+                    INFO_REBUILDINDEX_DESCRIPTION_REBUILD_DEGRADED.get());
+      argParser.addArgument(rebuildDegraded);
+
+
       tmpDirectory =
            new StringArgument("tmpdirectory", null, "tmpdirectory", false,
                    false, true, INFO_REBUILDINDEX_TEMP_DIR_PLACEHOLDER.get(),
@@ -251,7 +260,8 @@
     }
 
 
-    if (indexList.getValues().size() <= 0 && !rebuildAll.isPresent())
+    if (indexList.getValues().size() <= 0 && !rebuildAll.isPresent()
+        && !rebuildDegraded.isPresent())
     {
       Message message = ERR_REBUILDINDEX_REQUIRES_AT_LEAST_ONE_INDEX.get();
 
@@ -267,6 +277,23 @@
       out.println(argParser.getUsage());
       return 1;
     }
+
+    if(rebuildDegraded.isPresent() && indexList.isPresent())
+    {
+      Message msg = ERR_REBUILDINDEX_REBUILD_DEGRADED_ERROR.get();
+      err.println(wrapText(msg, MAX_LINE_WIDTH));
+      out.println(argParser.getUsage());
+      return 1;
+    }
+
+    if(rebuildAll.isPresent() && rebuildDegraded.isPresent())
+    {
+      Message msg = ERR_REBUILDINDEX_REBUILD_ALL_DEGRADED_ERROR.get();
+      err.println(wrapText(msg, MAX_LINE_WIDTH));
+      out.println(argParser.getUsage());
+      return 1;
+    }
+
     return process(argParser, initializeServer, out, err);
   }
 
@@ -402,10 +429,10 @@
 
       try
       {
-        ErrorLogPublisher errorLogPublisher =
+        ErrorLogPublisher<?> errorLogPublisher =
             TextErrorLogPublisher.getStartupTextErrorPublisher(
             new TextWriter.STREAM(out));
-        DebugLogPublisher debugLogPublisher =
+        DebugLogPublisher<?> debugLogPublisher =
             TextDebugLogPublisher.getStartupTextDebugPublisher(
             new TextWriter.STREAM(out));
         ErrorLogger.addErrorLogPublisher(errorLogPublisher);
@@ -520,8 +547,20 @@
       return 1;
     }
 
-   rebuildConfig.setRebuildAll(rebuildAll.isPresent());
-   rebuildConfig.setTmpDirectory(tmpDirectory.getValue());
+    if (rebuildAll.isPresent())
+    {
+      rebuildConfig.setRebuildMode(RebuildMode.ALL);
+    }
+    else if (rebuildDegraded.isPresent())
+    {
+      rebuildConfig.setRebuildMode(RebuildMode.DEGRADED);
+    }
+    else
+    {
+      rebuildConfig.setRebuildMode(RebuildMode.USER_DEFINED);
+    }
+
+    rebuildConfig.setTmpDirectory(tmpDirectory.getValue());
 
     // Launch the rebuild process.
     int returnCode = 0;
@@ -611,6 +650,16 @@
       attributes.add(
               new LDAPAttribute(ATTR_REBUILD_INDEX, values));
     }
+
+
+    if (rebuildDegraded.getValue() != null &&
+            !rebuildDegraded.getValue().equals(
+                rebuildDegraded.getDefaultValue())) {
+      values = new ArrayList<ByteString>(1);
+      values.add(ByteString.valueOf(REBUILD_DEGRADED));
+      attributes.add(
+              new LDAPAttribute(ATTR_REBUILD_INDEX, values));
+    }
   }
 
   /**
@@ -623,7 +672,7 @@
   /**
    * {@inheritDoc}
    */
-  public Class getTaskClass() {
+  public Class<?> getTaskClass() {
     return RebuildTask.class;
   }
 }
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
index 9080ad5..c93bdd1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestRebuildJob.java
@@ -23,7 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
- *      Portions Copyright 2011 ForgeRock AS
+ *      Portions Copyright 2011-2012 ForgeRock AS
  */
 package org.opends.server.backends.jeb;
 
@@ -33,6 +33,7 @@
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
 import org.opends.server.TestCaseUtils;
+import org.opends.server.backends.jeb.RebuildConfig.RebuildMode;
 import org.opends.server.config.ConfigConstants;
 import org.opends.server.tasks.TaskUtils;
 import static org.opends.server.util.ServerConstants.OC_TOP;
@@ -230,7 +231,26 @@
     cleanAndLoad(10);
     RebuildConfig rebuildConfig = new RebuildConfig();
     rebuildConfig.setBaseDN(baseDNs[0]);
-    rebuildConfig.setRebuildAll(true);
+    rebuildConfig.setRebuildMode(RebuildMode.ALL);
+
+    be=(BackendImpl) DirectoryServer.getBackend(beID);
+
+    TaskUtils.disableBackend(beID);
+
+    be.rebuildBackend(rebuildConfig);
+
+    assertEquals(verifyBackend(null), 0);
+
+    TaskUtils.enableBackend(beID);
+  }
+
+  @Test
+  public void testRebuildDegraded() throws Exception
+  {
+    cleanAndLoad(10);
+    RebuildConfig rebuildConfig = new RebuildConfig();
+    rebuildConfig.setBaseDN(baseDNs[0]);
+    rebuildConfig.setRebuildMode(RebuildMode.DEGRADED);
 
     be=(BackendImpl) DirectoryServer.getBackend(beID);
 

--
Gitblit v1.10.0