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

Jean-Noel Rouvignac
07.58.2014 3ab9614db1a1a1a30c271424c4189999bf71b87a
opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -26,7 +26,9 @@
 *      Portions Copyright 2014 Manuel Gaupp
 */
package org.opends.server.backends.jeb;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -35,6 +37,7 @@
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.forgerock.util.Utils;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn;
import org.opends.server.admin.std.server.LocalDBIndexCfg;
@@ -151,20 +154,8 @@
    if (indexConfig.getIndexType().contains(
            LocalDBIndexCfgDefn.IndexType.EQUALITY))
    {
      if (attrType.getEqualityMatchingRule() == null)
      {
        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "equality"));
      }
      Indexer equalityIndexer = new EqualityIndexer(attrType);
      this.equalityIndex = new Index(name + ".equality",
                                     equalityIndexer,
                                     state,
                                     indexEntryLimit,
                                     cursorEntryLimit,
                                     false,
                                     env,
                                     entryContainer);
      this.equalityIndex = buildExtIndex(
          name, attrType, attrType.getEqualityMatchingRule(), new EqualityIndexer());
    }
    if (indexConfig.getIndexType().contains(
@@ -184,57 +175,21 @@
    if (indexConfig.getIndexType().contains(
            LocalDBIndexCfgDefn.IndexType.SUBSTRING))
    {
      if (attrType.getSubstringMatchingRule() == null)
      {
        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "substring"));
      }
      Indexer substringIndexer = new SubstringIndexer(attrType, config);
      this.substringIndex = new Index(name + ".substring",
                                     substringIndexer,
                                     state,
                                     indexEntryLimit,
                                     cursorEntryLimit,
                                     false,
                                     env,
                                     entryContainer);
      this.substringIndex = buildExtIndex(
          name, attrType, attrType.getSubstringMatchingRule(), new SubstringIndexer(attrType, config));
    }
    if (indexConfig.getIndexType().contains(
            LocalDBIndexCfgDefn.IndexType.ORDERING))
    {
      if (attrType.getOrderingMatchingRule() == null)
      {
        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "ordering"));
      }
      Indexer orderingIndexer = new OrderingIndexer(attrType);
      this.orderingIndex = new Index(name + ".ordering",
                                     orderingIndexer,
                                     state,
                                     indexEntryLimit,
                                     cursorEntryLimit,
                                     false,
                                     env,
                                     entryContainer);
      this.orderingIndex = buildExtIndex(
          name, attrType, attrType.getOrderingMatchingRule(), new OrderingIndexer(attrType));
    }
    if (indexConfig.getIndexType().contains(
        LocalDBIndexCfgDefn.IndexType.APPROXIMATE))
    {
      if (attrType.getApproximateMatchingRule() == null)
      {
        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "approximate"));
      }
      Indexer approximateIndexer = new ApproximateIndexer(attrType);
      this.approximateIndex = new Index(name + ".approximate",
                                        approximateIndexer,
                                        state,
                                        indexEntryLimit,
                                        cursorEntryLimit,
                                        false,
                                        env,
                                        entryContainer);
      this.approximateIndex = buildExtIndex(
          name, attrType, attrType.getApproximateMatchingRule(), new ApproximateIndexer(attrType));
    }
    if (indexConfig.getIndexType().contains(
        LocalDBIndexCfgDefn.IndexType.EXTENSIBLE))
@@ -294,6 +249,26 @@
    }
  }
  private Index buildExtIndex(String name, AttributeType attrType,
      MatchingRule rule, ExtensibleIndexer extIndexer) throws ConfigException
  {
    if (rule == null)
    {
      throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(
          attrType, extIndexer.getExtensibleIndexID()));
    }
    Indexer indexer = new JEExtensibleIndexer(attrType, rule, extIndexer);
    return new Index(name + "." + extIndexer.getExtensibleIndexID(),
                                   indexer,
                                   state,
                                   indexConfig.getIndexEntryLimit(),
                                   cursorEntryLimit,
                                   false,
                                   env,
                                   entryContainer);
  }
  /**
   * Open the attribute index.
   *
@@ -302,30 +277,11 @@
   */
  public void open() throws DatabaseException
  {
    if (equalityIndex != null)
    {
      equalityIndex.open();
    }
    if (presenceIndex != null)
    {
      presenceIndex.open();
    }
    if (substringIndex != null)
    {
      substringIndex.open();
    }
    if (orderingIndex != null)
    {
      orderingIndex.open();
    }
    if (approximateIndex != null)
    {
      approximateIndex.open();
    }
    open(equalityIndex);
    open(presenceIndex);
    open(substringIndex);
    open(orderingIndex);
    open(approximateIndex);
    if(extensibleIndexes!=null)
    {
@@ -338,6 +294,14 @@
    indexConfig.addChangeListener(this);
  }
  private void open(Index index)
  {
    if (index != null)
    {
      index.open();
    }
  }
  /**
   * Close the attribute index.
   *
@@ -346,37 +310,12 @@
   */
  public void close() throws DatabaseException
  {
    if (equalityIndex != null)
    {
      equalityIndex.close();
    }
    if (presenceIndex != null)
    {
      presenceIndex.close();
    }
    if (substringIndex != null)
    {
      substringIndex.close();
    }
    if (orderingIndex != null)
    {
      orderingIndex.close();
    }
    if (approximateIndex != null)
    {
      approximateIndex.close();
    }
    Utils.closeSilently(equalityIndex, presenceIndex, substringIndex,
        orderingIndex, approximateIndex);
    if(extensibleIndexes!=null)
    {
      for(Index extensibleIndex:extensibleIndexes.getIndexes())
      {
        extensibleIndex.close();
      }
      Utils.closeSilently(extensibleIndexes.getIndexes());
    }
    indexConfig.removeChangeListener(this);
@@ -416,33 +355,13 @@
                          Entry entry)
       throws DatabaseException, DirectoryException
  {
    boolean success = false;
    boolean success = true;
    if (equalityIndex != null
        && !equalityIndex.addEntry(buffer, entryID, entry))
    {
      success = false;
    }
    if (presenceIndex != null
        && !presenceIndex.addEntry(buffer, entryID, entry))
    {
      success = false;
    }
    if (substringIndex != null
        && !substringIndex.addEntry(buffer, entryID, entry))
    {
      success = false;
    }
    if (orderingIndex != null
        && !orderingIndex.addEntry(buffer, entryID, entry))
    {
      success = false;
    }
    if (approximateIndex != null
        && !approximateIndex.addEntry(buffer, entryID, entry))
    {
      success = false;
    }
    success = addEntry(equalityIndex, buffer, entryID, entry, success);
    success = addEntry(presenceIndex, buffer, entryID, entry, success);
    success = addEntry(substringIndex, buffer, entryID, entry, success);
    success = addEntry(orderingIndex, buffer, entryID, entry, success);
    success = addEntry(approximateIndex, buffer, entryID, entry, success);
    if(extensibleIndexes!=null)
    {
@@ -458,6 +377,15 @@
    return success;
  }
  private boolean addEntry(Index index, IndexBuffer buffer, EntryID entryID,
      Entry entry, boolean success) throws DirectoryException, DatabaseException
  {
    if (index != null && !index.addEntry(buffer, entryID, entry))
    {
      return false;
    }
    return success;
  }
  /**
   * Update the attribute index for a new entry.
@@ -475,27 +403,11 @@
  {
    boolean success = true;
    if (equalityIndex != null && !equalityIndex.addEntry(txn, entryID, entry))
    {
      success = false;
    }
    if (presenceIndex != null && !presenceIndex.addEntry(txn, entryID, entry))
    {
      success = false;
    }
    if (substringIndex != null && !substringIndex.addEntry(txn, entryID, entry))
    {
      success = false;
    }
    if (orderingIndex != null && !orderingIndex.addEntry(txn, entryID, entry))
    {
      success = false;
    }
    if (approximateIndex != null
        && !approximateIndex.addEntry(txn, entryID, entry))
    {
      success = false;
    }
    success = addEntry(equalityIndex, txn, entryID, entry, success);
    success = addEntry(presenceIndex, txn, entryID, entry, success);
    success = addEntry(substringIndex, txn, entryID, entry, success);
    success = addEntry(orderingIndex, txn, entryID, entry, success);
    success = addEntry(approximateIndex, txn, entryID, entry, success);
    if(extensibleIndexes!=null)
    {
@@ -511,6 +423,17 @@
    return success;
  }
  private boolean addEntry(Index index, Transaction txn, EntryID entryID,
      Entry entry, boolean success) throws DirectoryException, DatabaseException
  {
    if (index != null && !index.addEntry(txn, entryID, entry))
    {
      return false;
    }
    return success;
  }
  /**
   * Update the attribute index for a deleted entry.
   *
@@ -524,30 +447,11 @@
                          Entry entry)
       throws DatabaseException, DirectoryException
  {
    if (equalityIndex != null)
    {
      equalityIndex.removeEntry(buffer, entryID, entry);
    }
    if (presenceIndex != null)
    {
      presenceIndex.removeEntry(buffer, entryID, entry);
    }
    if (substringIndex != null)
    {
      substringIndex.removeEntry(buffer, entryID, entry);
    }
    if (orderingIndex != null)
    {
      orderingIndex.removeEntry(buffer, entryID, entry);
    }
    if(approximateIndex != null)
    {
      approximateIndex.removeEntry(buffer, entryID, entry);
    }
    removeEntry(equalityIndex, buffer, entryID, entry);
    removeEntry(presenceIndex, buffer, entryID, entry);
    removeEntry(substringIndex, buffer, entryID, entry);
    removeEntry(orderingIndex, buffer, entryID, entry);
    removeEntry(approximateIndex, buffer, entryID, entry);
    if(extensibleIndexes!=null)
    {
@@ -558,6 +462,15 @@
    }
  }
  private void removeEntry(Index index, IndexBuffer buffer, EntryID entryID,
      Entry entry) throws DirectoryException, DatabaseException
  {
    if (index != null)
    {
      index.removeEntry(buffer, entryID, entry);
    }
  }
  /**
   * Update the attribute index for a deleted entry.
   *
@@ -570,30 +483,11 @@
  public void removeEntry(Transaction txn, EntryID entryID, Entry entry)
       throws DatabaseException, DirectoryException
  {
    if (equalityIndex != null)
    {
      equalityIndex.removeEntry(txn, entryID, entry);
    }
    if (presenceIndex != null)
    {
      presenceIndex.removeEntry(txn, entryID, entry);
    }
    if (substringIndex != null)
    {
      substringIndex.removeEntry(txn, entryID, entry);
    }
    if (orderingIndex != null)
    {
      orderingIndex.removeEntry(txn, entryID, entry);
    }
    if(approximateIndex != null)
    {
      approximateIndex.removeEntry(txn, entryID, entry);
    }
    removeEntry(equalityIndex, txn, entryID, entry);
    removeEntry(presenceIndex, txn, entryID, entry);
    removeEntry(substringIndex, txn, entryID, entry);
    removeEntry(orderingIndex, txn, entryID, entry);
    removeEntry(approximateIndex, txn, entryID, entry);
    if(extensibleIndexes!=null)
    {
@@ -604,6 +498,15 @@
    }
  }
  private void removeEntry(Index index, Transaction txn, EntryID entryID,
      Entry entry) throws DirectoryException, DatabaseException
  {
    if (index != null)
    {
      index.removeEntry(txn, entryID, entry);
    }
  }
  /**
   * Update the index to reflect a sequence of modifications in a Modify
   * operation.
@@ -623,30 +526,11 @@
                          List<Modification> mods)
       throws DatabaseException
  {
    if (equalityIndex != null)
    {
      equalityIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
    if (presenceIndex != null)
    {
      presenceIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
    if (substringIndex != null)
    {
      substringIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
    if (orderingIndex != null)
    {
      orderingIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
    if (approximateIndex != null)
    {
      approximateIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
    modifyEntry(equalityIndex, txn, entryID, oldEntry, newEntry, mods);
    modifyEntry(presenceIndex, txn, entryID, oldEntry, newEntry, mods);
    modifyEntry(substringIndex, txn, entryID, oldEntry, newEntry, mods);
    modifyEntry(orderingIndex, txn, entryID, oldEntry, newEntry, mods);
    modifyEntry(approximateIndex, txn, entryID, oldEntry, newEntry, mods);
    if(extensibleIndexes!=null)
    {
@@ -657,6 +541,16 @@
    }
  }
  private void modifyEntry(Index index, Transaction txn, EntryID entryID,
      Entry oldEntry, Entry newEntry, List<Modification> mods)
      throws DatabaseException
  {
    if (index != null)
    {
      index.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
    }
  }
  /**
   * Update the index to reflect a sequence of modifications in a Modify
   * operation.
@@ -676,30 +570,11 @@
                          List<Modification> mods)
       throws DatabaseException
  {
    if (equalityIndex != null)
    {
      equalityIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
    if (presenceIndex != null)
    {
      presenceIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
    if (substringIndex != null)
    {
      substringIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
    if (orderingIndex != null)
    {
      orderingIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
    if (approximateIndex != null)
    {
      approximateIndex.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
    modifyEntry(equalityIndex, buffer, entryID, oldEntry, newEntry, mods);
    modifyEntry(presenceIndex, buffer, entryID, oldEntry, newEntry, mods);
    modifyEntry(substringIndex, buffer, entryID, oldEntry, newEntry, mods);
    modifyEntry(orderingIndex, buffer, entryID, oldEntry, newEntry, mods);
    modifyEntry(approximateIndex, buffer, entryID, oldEntry, newEntry, mods);
    if(extensibleIndexes!=null)
    {
@@ -710,6 +585,16 @@
    }
  }
  private void modifyEntry(Index index, IndexBuffer buffer, EntryID entryID,
      Entry oldEntry, Entry newEntry, List<Modification> mods)
      throws DatabaseException
  {
    if (index != null)
    {
      index.modifyEntry(buffer, entryID, oldEntry, newEntry, mods);
    }
  }
  /**
   * Makes a byte array representing a substring index key for
   * one substring of a value.
@@ -735,8 +620,7 @@
   * @return A set of index keys.
   */
  Set<ByteString> substringKeys(byte[] value)
  {
    // FIXME replace this code with SDK's
  { // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys()
    // Eliminate duplicates by putting the keys into a set.
@@ -769,8 +653,7 @@
   * @return The candidate entry IDs.
   */
  private EntryIDSet matchSubstring(byte[] bytes)
  {
    // FIXME replace this code with SDK's
  { // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()
    int substrLength = indexConfig.getSubstringLength();
@@ -855,8 +738,7 @@
   * @return The candidate entry IDs.
   */
  private EntryIDSet matchInitialSubstring(byte[] bytes)
  {
    // FIXME replace this code with SDK's
  { // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()
    // Iterate through all the keys that have this value as the prefix.
@@ -1051,74 +933,10 @@
      SearchFilter filter, StringBuilder debugBuffer,
      DatabaseEnvironmentMonitor monitor)
  {
    if (orderingIndex == null)
    {
      if(monitor.isFilterUseEnabled())
      {
        monitor.updateStats(filter,
            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("ordering",
                indexConfig.getAttribute().getNameOrOID()));
      }
      return new EntryIDSet();
    }
    try
    {
      // Set the lower bound for a range search.
      // Use the ordering matching rule to normalize the value.
      OrderingMatchingRule orderingRule =
           filter.getAttributeType().getOrderingMatchingRule();
      byte[] lower = orderingRule.normalizeAttributeValue(
           filter.getAssertionValue().getValue()).toByteArray();
      // Set the upper bound to 0 to search all keys greater then the lower
      // bound.
      byte[] upper = new byte[0];
      if(debugBuffer != null)
      {
        debugBuffer.append("[INDEX:");
        debugBuffer.append(indexConfig.getAttribute().getNameOrOID());
        debugBuffer.append(".");
        debugBuffer.append("ordering]");
      }
      // Read the range: lower <= keys < upper.
      EntryIDSet idSet = orderingIndex.readRange(lower, upper, true, false);
      if(monitor.isFilterUseEnabled())
      {
        if(idSet.isDefined())
        {
          monitor.updateStats(filter, idSet.size());
        }
        else if(!orderingIndex.isTrusted())
        {
          monitor.updateStats(filter,
              INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get(
                  orderingIndex.getName()));
        }
        else if(orderingIndex.isRebuildRunning())
        {
          monitor.updateStats(filter,
              INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get(
                  orderingIndex.getName()));
        }
        else
        {
          monitor.updateStats(filter,
              INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get(
                  orderingIndex.getName()));
        }
      }
      return idSet;
    }
    catch (DecodeException e)
    {
      logger.traceException(e);
      return new EntryIDSet();
    }
    return evaluateOrderingFilter(filter, true, debugBuffer, monitor);
  }
  /**
   * Retrieve the entry IDs that might match a less-or-equal filter.
   *
@@ -1135,6 +953,14 @@
                                              StringBuilder debugBuffer,
                                             DatabaseEnvironmentMonitor monitor)
  {
    return evaluateOrderingFilter(filter, false, debugBuffer, monitor);
  }
  private EntryIDSet evaluateOrderingFilter(SearchFilter filter,
      boolean greater, StringBuilder debugBuffer,
      DatabaseEnvironmentMonitor monitor)
  {
    if (orderingIndex == null)
    {
      if(monitor.isFilterUseEnabled())
@@ -1148,16 +974,28 @@
    try
    {
      // Set the lower bound to 0 to start the range search from the smallest
      // key.
      byte[] lower = new byte[0];
      // Set the upper bound for a range search.
      // Use the ordering matching rule to normalize the value.
      OrderingMatchingRule orderingRule =
           filter.getAttributeType().getOrderingMatchingRule();
      byte[] upper = orderingRule.normalizeAttributeValue(
           filter.getAssertionValue().getValue()).toByteArray();
      // FIXME JNR this looks wrong, it should use normalizeAssertionValue()
      byte[] normalizedValue = orderingRule.normalizeAttributeValue(
          filter.getAssertionValue().getValue()).toByteArray();
      // Set the lower and upper bounds for a range search.
      byte[] lower;
      byte[] upper;
      if (greater)
      {
        // Set upper bound to 0 to search all keys greater than the lower bound.
        lower = normalizedValue;
        upper = new byte[0];
      }
      else
      {
        // Set lower bound to 0 to start the range search from the smallest key.
        lower = new byte[0];
        upper = normalizedValue;
      }
      if(debugBuffer != null)
      {
@@ -1167,8 +1005,8 @@
        debugBuffer.append("ordering]");
      }
      // Read the range: lower < keys <= upper.
      EntryIDSet idSet = orderingIndex.readRange(lower, upper, false, true);
      // Read the range: lower <= keys < upper OR lower < keys <= upper
      EntryIDSet idSet = orderingIndex.readRange(lower, upper, greater, !greater);
      if(monitor.isFilterUseEnabled())
      {
        if(idSet.isDefined())
@@ -1506,6 +1344,7 @@
      ApproximateMatchingRule approximateMatchingRule =
          approximateFilter.getAttributeType().getApproximateMatchingRule();
      // Make a key from the normalized assertion value.
      // FIXME JNR this looks wrong, it should use normalizeAssertionValue()
      byte[] keyBytes =
           approximateMatchingRule.normalizeAttributeValue(
               approximateFilter.getAssertionValue().getValue()).toByteArray();
@@ -1648,30 +1487,11 @@
   */
  public void listDatabases(List<DatabaseContainer> dbList)
  {
    if (equalityIndex != null)
    {
      dbList.add(equalityIndex);
    }
    if (presenceIndex != null)
    {
      dbList.add(presenceIndex);
    }
    if (substringIndex != null)
    {
      dbList.add(substringIndex);
    }
    if (orderingIndex != null)
    {
      dbList.add(orderingIndex);
    }
    if (approximateIndex != null)
    {
      dbList.add(approximateIndex);
    }
    addIfNotNull(dbList, equalityIndex);
    addIfNotNull(dbList, presenceIndex);
    addIfNotNull(dbList, substringIndex);
    addIfNotNull(dbList, orderingIndex);
    addIfNotNull(dbList, approximateIndex);
    if(extensibleIndexes!=null)
    {
@@ -1682,6 +1502,14 @@
    }
  }
  private void addIfNotNull(Collection<? super Index> dbList, Index index)
  {
    if (index != null)
    {
      dbList.add(index);
    }
  }
  /**
   * Get a string representation of this object.
   * @return return A string representation of this object.
@@ -1748,7 +1576,8 @@
  public synchronized ConfigChangeResult applyConfigurationChange(
      LocalDBIndexCfg cfg)
  {
    boolean adminActionRequired = false;
    // this method is not perf sensitive, using an AtomicBoolean will not hurt
    AtomicBoolean adminActionRequired = new AtomicBoolean(false);
    ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
    try
    {
@@ -1762,32 +1591,16 @@
      {
        if (equalityIndex == null)
        {
          // Adding equality index
          Indexer equalityIndexer = new EqualityIndexer(attrType);
          equalityIndex = new Index(name + ".equality",
                                    equalityIndexer,
                                    state,
                                    indexEntryLimit,
                                    cursorEntryLimit,
                                    false,
                                    env,
                                    entryContainer);
          equalityIndex.open();
          if(!equalityIndex.isTrusted())
          {
            adminActionRequired = true;
            messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                equalityIndex.getName()));
          }
          EqualityIndexer indexer = new EqualityIndexer();
          Indexer extIndexer = new JEExtensibleIndexer(attrType, attrType.getEqualityMatchingRule(), indexer);
          equalityIndex = openNewIndex(name, extIndexer, indexer, adminActionRequired, messages);
        }
        else
        {
          // already exists. Just update index entry limit.
          if(this.equalityIndex.setIndexEntryLimit(indexEntryLimit))
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            LocalizableMessage message =
                    NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                            equalityIndex.getName());
@@ -1806,13 +1619,6 @@
            entryContainer.deleteDatabase(equalityIndex);
            equalityIndex = null;
          }
          catch(DatabaseException de)
          {
            messages.add(LocalizableMessage.raw(
                    StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -1837,7 +1643,7 @@
          if(!presenceIndex.isTrusted())
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                presenceIndex.getName()));
          }
@@ -1847,8 +1653,7 @@
          // already exists. Just update index entry limit.
          if(this.presenceIndex.setIndexEntryLimit(indexEntryLimit))
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            LocalizableMessage message =
                    NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                            presenceIndex.getName());
@@ -1866,13 +1671,6 @@
            entryContainer.deleteDatabase(presenceIndex);
            presenceIndex = null;
          }
          catch(DatabaseException de)
          {
            messages.add(LocalizableMessage.raw(
                    StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -1882,43 +1680,27 @@
      if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.SUBSTRING))
      {
        SubstringIndexer indexer = new SubstringIndexer(attrType, config);
        Indexer extIndexer = new JEExtensibleIndexer(attrType, attrType.getSubstringMatchingRule(), indexer);
        if(substringIndex == null)
        {
          Indexer substringIndexer = new SubstringIndexer(attrType, config);
          substringIndex = new Index(name + ".substring",
                                     substringIndexer,
                                     state,
                                     indexEntryLimit,
                                     cursorEntryLimit,
                                     false,
                                     env,
                                     entryContainer);
          substringIndex.open();
          if(!substringIndex.isTrusted())
          {
            adminActionRequired = true;
            messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                substringIndex.getName()));
          }
          substringIndex = openNewIndex(name, extIndexer, indexer, adminActionRequired, messages);
        }
        else
        {
          // already exists. Just update index entry limit.
          if(this.substringIndex.setIndexEntryLimit(indexEntryLimit))
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            LocalizableMessage message =
                    NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                            substringIndex.getName());
            messages.add(message);
          }
          if(indexConfig.getSubstringLength() !=
              cfg.getSubstringLength())
          if (indexConfig.getSubstringLength() != cfg.getSubstringLength())
          {
            Indexer substringIndexer = new SubstringIndexer(attrType, config);
            this.substringIndex.setIndexer(substringIndexer);
            this.substringIndex.setIndexer(extIndexer);
          }
        }
      }
@@ -1932,13 +1714,6 @@
            entryContainer.deleteDatabase(substringIndex);
            substringIndex = null;
          }
          catch(DatabaseException de)
          {
            messages.add(LocalizableMessage.raw(
                    StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -1950,31 +1725,16 @@
      {
        if(orderingIndex == null)
        {
          Indexer orderingIndexer = new OrderingIndexer(attrType);
          orderingIndex = new Index(name + ".ordering",
                                    orderingIndexer,
                                    state,
                                    indexEntryLimit,
                                    cursorEntryLimit,
                                    false,
                                    env,
                                    entryContainer);
          orderingIndex.open();
          if(!orderingIndex.isTrusted())
          {
            adminActionRequired = true;
            messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                orderingIndex.getName()));
          }
          OrderingIndexer indexer = new OrderingIndexer(attrType);
          Indexer extIndexer = new JEExtensibleIndexer(attrType, attrType.getOrderingMatchingRule(), indexer);
          orderingIndex = openNewIndex(name, extIndexer, indexer, adminActionRequired, messages);
        }
        else
        {
          // already exists. Just update index entry limit.
          if(this.orderingIndex.setIndexEntryLimit(indexEntryLimit))
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            LocalizableMessage message =
                    NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                            orderingIndex.getName());
@@ -1992,13 +1752,6 @@
            entryContainer.deleteDatabase(orderingIndex);
            orderingIndex = null;
          }
          catch(DatabaseException de)
          {
            messages.add(LocalizableMessage.raw(
                    StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -2011,31 +1764,16 @@
      {
        if(approximateIndex == null)
        {
          Indexer approximateIndexer = new ApproximateIndexer(attrType);
          approximateIndex = new Index(name + ".approximate",
                                       approximateIndexer,
                                       state,
                                       indexEntryLimit,
                                       cursorEntryLimit,
                                       false,
                                       env,
                                       entryContainer);
          approximateIndex.open();
          if(!approximateIndex.isTrusted())
          {
            adminActionRequired = true;
            messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                approximateIndex.getName()));
          }
          ApproximateIndexer indexer = new ApproximateIndexer(attrType);
          Indexer extIndexer = new JEExtensibleIndexer(attrType, attrType.getApproximateMatchingRule(), indexer);
          approximateIndex = openNewIndex(name, extIndexer, indexer, adminActionRequired, messages);
        }
        else
        {
          // already exists. Just update index entry limit.
          if(this.approximateIndex.setIndexEntryLimit(indexEntryLimit))
          {
            adminActionRequired = true;
            adminActionRequired.set(true);
            LocalizableMessage message =
                    NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                            approximateIndex.getName());
@@ -2053,13 +1791,6 @@
            entryContainer.deleteDatabase(approximateIndex);
            approximateIndex = null;
          }
          catch(DatabaseException de)
          {
            messages.add(
                    LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -2114,7 +1845,7 @@
              if(!extensibleIndex.isTrusted())
              {
                adminActionRequired = true;
                adminActionRequired.set(true);
                messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(
                    extensibleIndex.getName()));
              }
@@ -2124,7 +1855,7 @@
              Index extensibleIndex = extensibleIndexes.getIndex(indexID);
              if(extensibleIndex.setIndexEntryLimit(indexEntryLimit))
              {
                adminActionRequired = true;
                adminActionRequired.set(true);
                LocalizableMessage message =
                      NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(
                              extensibleIndex.getName());
@@ -2201,13 +1932,6 @@
              }
            }
          }
          catch(DatabaseException de)
          {
            messages.add(
                  LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -2228,13 +1952,6 @@
            }
            extensibleIndexes.deleteAll();
          }
          catch(DatabaseException de)
          {
            messages.add(
                  LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
            return new ConfigChangeResult(
                DirectoryServer.getServerErrorResultCode(), false, messages);
          }
          finally
          {
            entryContainer.exclusiveLock.unlock();
@@ -2244,17 +1961,34 @@
      indexConfig = cfg;
      return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
                                    messages);
      return new ConfigChangeResult(
          ResultCode.SUCCESS, adminActionRequired.get(), messages);
    }
    catch(Exception e)
    {
      messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e)));
      return new ConfigChangeResult(
          DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages);
          DirectoryServer.getServerErrorResultCode(), adminActionRequired.get(), messages);
    }
  }
  private Index openNewIndex(String name, Indexer indexer, ExtensibleIndexer extIndexer,
      AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
  {
    Index index = new Index(name + "." + extIndexer.getExtensibleIndexID(), indexer,
        state, indexConfig.getIndexEntryLimit(), cursorEntryLimit, false, env,
        entryContainer);
    index.open();
    if (!index.isTrusted())
    {
      adminActionRequired.set(true);
      messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(index
          .getName()));
    }
    return index;
  }
  /**
   * Set the index truststate.
   * @param txn A database transaction, or null if none is required.
@@ -2265,30 +1999,11 @@
  public synchronized void setTrusted(Transaction txn, boolean trusted)
      throws DatabaseException
  {
    if (equalityIndex != null)
    {
      equalityIndex.setTrusted(txn, trusted);
    }
    if (presenceIndex != null)
    {
      presenceIndex.setTrusted(txn, trusted);
    }
    if (substringIndex != null)
    {
      substringIndex.setTrusted(txn, trusted);
    }
    if (orderingIndex != null)
    {
      orderingIndex.setTrusted(txn, trusted);
    }
    if (approximateIndex != null)
    {
      approximateIndex.setTrusted(txn, trusted);
    }
    setTrusted(equalityIndex, txn, trusted);
    setTrusted(presenceIndex, txn, trusted);
    setTrusted(substringIndex, txn, trusted);
    setTrusted(orderingIndex, txn, trusted);
    setTrusted(approximateIndex, txn, trusted);
    if(extensibleIndexes!=null)
    {
@@ -2299,33 +2014,25 @@
    }
  }
  private void setTrusted(Index index, Transaction txn, boolean trusted)
  {
    if (index != null)
    {
      index.setTrusted(txn, trusted);
    }
  }
  /**
   * Return true iff this index is trusted.
   * @return the trusted state of this index
   */
  public boolean isTrusted()
  {
    if (equalityIndex != null && !equalityIndex.isTrusted())
    {
      return false;
    }
    if (presenceIndex != null && !presenceIndex.isTrusted())
    {
      return false;
    }
    if (substringIndex != null && !substringIndex.isTrusted())
    {
      return false;
    }
    if (orderingIndex != null && !orderingIndex.isTrusted())
    {
      return false;
    }
    if (approximateIndex != null && !approximateIndex.isTrusted())
    if ((equalityIndex != null && !equalityIndex.isTrusted())
        || (presenceIndex != null && !presenceIndex.isTrusted())
        || (substringIndex != null && !substringIndex.isTrusted())
        || (orderingIndex != null && !orderingIndex.isTrusted())
        || (approximateIndex != null && !approximateIndex.isTrusted()))
    {
      return false;
    }
@@ -2351,30 +2058,11 @@
   */
  public synchronized void setRebuildStatus(boolean rebuildRunning)
  {
    if (equalityIndex != null)
    {
      equalityIndex.setRebuildStatus(rebuildRunning);
    }
    if (presenceIndex != null)
    {
      presenceIndex.setRebuildStatus(rebuildRunning);
    }
    if (substringIndex != null)
    {
      substringIndex.setRebuildStatus(rebuildRunning);
    }
    if (orderingIndex != null)
    {
      orderingIndex.setRebuildStatus(rebuildRunning);
    }
    if (approximateIndex != null)
    {
      approximateIndex.setRebuildStatus(rebuildRunning);
    }
    setRebuildStatus(rebuildRunning, equalityIndex);
    setRebuildStatus(rebuildRunning, presenceIndex);
    setRebuildStatus(rebuildRunning, substringIndex);
    setRebuildStatus(rebuildRunning, orderingIndex);
    setRebuildStatus(rebuildRunning, approximateIndex);
    if(extensibleIndexes!=null)
    {
@@ -2385,6 +2073,14 @@
    }
  }
  private void setRebuildStatus(boolean rebuildRunning, Index index)
  {
    if (index != null)
    {
      index.setRebuildStatus(rebuildRunning);
    }
  }
  /**
   * Get the JE database name prefix for indexes in this attribute index.
   *
@@ -2466,30 +2162,11 @@
  public Collection<Index> getAllIndexes() {
    LinkedHashSet<Index> indexes = new LinkedHashSet<Index>();
    if (equalityIndex != null)
    {
      indexes.add(equalityIndex);
    }
    if (presenceIndex != null)
    {
      indexes.add(presenceIndex);
    }
    if (substringIndex != null)
    {
      indexes.add(substringIndex);
    }
    if (orderingIndex != null)
    {
      indexes.add(orderingIndex);
    }
    if (approximateIndex != null)
    {
      indexes.add(approximateIndex);
    }
    addIfNotNull(indexes, equalityIndex);
    addIfNotNull(indexes, presenceIndex);
    addIfNotNull(indexes, substringIndex);
    addIfNotNull(indexes, orderingIndex);
    addIfNotNull(indexes, approximateIndex);
    if(extensibleIndexes!=null)
    {