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

boli
29.45.2008 4e0231d95ce73b8354afa7827cba077b9b105c85
This patch resolves potential deadlocks in the JE backend when performing modify operations. This is done by ensuring the indexer orders the keys to add and delete together before DB accesses are performed. This patch also removes passing the JE transaction object into the indexer methods since it is not needed.

Fix for issue 3213
12 files modified
867 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java 147 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java 148 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ID2CIndexer.java 37 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ID2SIndexer.java 40 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Index.java 57 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Indexer.java 29 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java 148 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java 42 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java 173 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/BufferManager.java 6 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java 36 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
@@ -26,8 +26,6 @@
 */
package org.opends.server.backends.jeb;
import com.sleepycat.je.Transaction;
import java.util.*;
import org.opends.server.types.*;
@@ -99,13 +97,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> keys)
  public void indexEntry(Entry entry, Set<byte[]> keys)
  {
    List<Attribute> attrList =
         entry.getAttribute(attributeType);
@@ -115,51 +110,22 @@
    }
  }
    /**
  /**
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn,
                           Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
@@ -168,48 +134,20 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
                          Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
  /**
@@ -256,4 +194,65 @@
      }
    }
  }
  /**
   * Generate the set of index keys for an attribute.
   * @param attrList The attribute to be indexed.
   * @param modifiedKeys The map into which the modified
   * keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexAttribute(List<Attribute> attrList,
                              Map<byte[], Boolean> modifiedKeys,
                              Boolean insert)
  {
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      indexValues(attr.getValues(), modifiedKeys, insert);
    }
  }
  /**
   * Generate the set of index keys for a set of attribute values.
   * @param values The set of attribute values to be indexed.
   * @param modifiedKeys The map into which the modified
   *  keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexValues(Set<AttributeValue> values,
                           Map<byte[], Boolean> modifiedKeys,
                           Boolean insert)
  {
    if (values == null) return;
    for (AttributeValue value : values)
    {
      try
      {
        byte[] keyBytes =
            approximateRule.normalizeValue(value.getValue()).value();
        Boolean cInsert = modifiedKeys.get(keyBytes);
        if(cInsert == null)
        {
          modifiedKeys.put(keyBytes, insert);
        }
        else if(!cInsert.equals(insert))
        {
          modifiedKeys.remove(keyBytes);
        }
      }
      catch (DirectoryException e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -30,9 +30,6 @@
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseException;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
@@ -103,14 +100,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public void indexEntry(Transaction txn, Entry entry,
                         Set<byte[]> keys) throws DatabaseException
  public void indexEntry(Entry entry, Set<byte[]> keys)
  {
    List<Attribute> attrList =
         entry.getAttribute(attributeType);
@@ -126,48 +119,18 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn, Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
      throws DatabaseException
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
@@ -177,50 +140,20 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
      throws DatabaseException
                          Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
  /**
@@ -267,4 +200,63 @@
    }
  }
  /**
   * Generate the set of index keys for an attribute.
   * @param attrList The attribute to be indexed.
   * @param modifiedKeys The map into which the modified
   * keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexAttribute(List<Attribute> attrList,
                              Map<byte[], Boolean> modifiedKeys,
                              Boolean insert)
  {
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      indexValues(attr.getValues(), modifiedKeys, insert);
    }
  }
  /**
   * Generate the set of index keys for a set of attribute values.
   * @param values The set of attribute values to be indexed.
   * @param modifiedKeys The map into which the modified
   *  keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexValues(Set<AttributeValue> values,
                           Map<byte[], Boolean> modifiedKeys,
                           Boolean insert)
  {
    if (values == null) return;
    for (AttributeValue value : values)
    {
      try
      {
        byte[] keyBytes = value.getNormalizedValue().value();
        Boolean cInsert = modifiedKeys.get(keyBytes);
        if(cInsert == null)
        {
          modifiedKeys.put(keyBytes, insert);
        }
        else if(!cInsert.equals(insert))
        {
          modifiedKeys.remove(keyBytes);
        }
      }
      catch (DirectoryException e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ID2CIndexer.java
@@ -30,14 +30,8 @@
import org.opends.server.types.Modification;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
 * Implementation of an Indexer for the children index.
@@ -82,15 +76,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param addKeys The set into which the generated keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> addKeys)
       throws DatabaseException
  public void indexEntry(Entry entry, Set<byte[]> addKeys)
  {
    // The superior entry IDs are in the entry attachment.
    ArrayList ids = (ArrayList)entry.getAttachment();
@@ -111,16 +100,12 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn, Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    // Nothing to do.
  }
@@ -131,20 +116,14 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
       throws DatabaseException
                          Map<byte[], Boolean> modifiedKeys)
  {
    // Nothing to do.
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ID2SIndexer.java
@@ -29,15 +29,9 @@
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseEntry;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
 * Implementation of an Indexer for the subtree index.
@@ -81,15 +75,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param addKeys The set into which the generated keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> addKeys)
       throws DatabaseException
  public void indexEntry(Entry entry, Set<byte[]> addKeys)
  {
    // The superior entry IDs are in the entry attachment.
    ArrayList ids = (ArrayList)entry.getAttachment();
@@ -110,19 +99,12 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn,
                           Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
       throws DatabaseException
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    // Nothing to do.
  }
@@ -133,20 +115,14 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
       throws DatabaseException
                          Map<byte[], Boolean> modifiedKeys)
  {
    // Nothing to do.
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Index.java
@@ -1154,7 +1154,7 @@
    HashSet<byte[]> addKeys = new HashSet<byte[]>();
    boolean success = true;
    indexer.indexEntry(null, entry, addKeys);
    indexer.indexEntry(entry, addKeys);
    for (byte[] keyBytes : addKeys)
    {
@@ -1184,7 +1184,7 @@
    TreeSet<byte[]> addKeys = new TreeSet<byte[]>(indexer.getComparator());
    boolean success = true;
    indexer.indexEntry(txn, entry, addKeys);
    indexer.indexEntry(entry, addKeys);
    DatabaseEntry key = new DatabaseEntry();
    for (byte[] keyBytes : addKeys)
@@ -1213,7 +1213,7 @@
  {
    HashSet<byte[]> delKeys = new HashSet<byte[]>();
    indexer.indexEntry(null, entry, delKeys);
    indexer.indexEntry(entry, delKeys);
    for (byte[] keyBytes : delKeys)
    {
@@ -1235,7 +1235,7 @@
  {
    TreeSet<byte[]> delKeys = new TreeSet<byte[]>(indexer.getComparator());
    indexer.indexEntry(txn, entry, delKeys);
    indexer.indexEntry(entry, delKeys);
    DatabaseEntry key = new DatabaseEntry();
    for (byte[] keyBytes : delKeys)
@@ -1264,22 +1264,23 @@
                          List<Modification> mods)
       throws DatabaseException
  {
    TreeSet<byte[]> addKeys = new TreeSet<byte[]>(indexer.getComparator());
    TreeSet<byte[]> delKeys = new TreeSet<byte[]>(indexer.getComparator());
    TreeMap<byte[], Boolean> modifiedKeys =
        new TreeMap<byte[], Boolean>(indexer.getComparator());
    indexer.modifyEntry(txn, oldEntry, newEntry, mods, addKeys, delKeys);
    indexer.modifyEntry(oldEntry, newEntry, mods, modifiedKeys);
    DatabaseEntry key = new DatabaseEntry();
    for (byte[] keyBytes : delKeys)
    for (Map.Entry<byte[], Boolean> modifiedKey : modifiedKeys.entrySet())
    {
      key.setData(keyBytes);
      removeID(txn, key, entryID);
    }
    for (byte[] keyBytes : addKeys)
    {
      key.setData(keyBytes);
      insertID(txn, key, entryID);
      key.setData(modifiedKey.getKey());
      if(modifiedKey.getValue())
      {
        insertID(txn, key, entryID);
      }
      else
      {
        removeID(txn, key, entryID);
      }
    }
  }
@@ -1299,21 +1300,21 @@
                          Entry oldEntry,
                          Entry newEntry,
                          List<Modification> mods)
       throws DatabaseException
      throws DatabaseException
  {
    TreeSet<byte[]> addKeys = new TreeSet<byte[]>(indexer.getComparator());
    TreeSet<byte[]> delKeys = new TreeSet<byte[]>(indexer.getComparator());
    HashMap<byte[], Boolean> modifiedKeys = new HashMap<byte[], Boolean>();
    indexer.modifyEntry(null, oldEntry, newEntry, mods, addKeys, delKeys);
    for (byte[] keyBytes : delKeys)
    indexer.modifyEntry(oldEntry, newEntry, mods, modifiedKeys);
    for (Map.Entry<byte[], Boolean> modifiedKey : modifiedKeys.entrySet())
    {
      removeID(buffer, keyBytes, entryID);
    }
    for (byte[] keyBytes : addKeys)
    {
      insertID(buffer, keyBytes, entryID);
      if(modifiedKey.getValue())
      {
        insertID(buffer, modifiedKey.getKey(), entryID);
      }
      else
      {
        removeID(buffer, modifiedKey.getKey(), entryID);
      }
    }
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Indexer.java
@@ -29,11 +29,11 @@
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Transaction;
import java.util.Comparator;
import java.util.Set;
import java.util.List;
import java.util.Map;
/**
 * This class attempts to abstract the generation and comparison of keys
@@ -52,51 +52,38 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public abstract void indexEntry(Transaction txn, Entry entry,
                                Set<byte[]> keys)
  public abstract void indexEntry(Entry entry, Set<byte[]> keys)
       throws DatabaseException;
  /**
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public abstract void replaceEntry(Transaction txn,
                                    Entry oldEntry, Entry newEntry,
                                    Set<byte[]> addKeys,
                                    Set<byte[]> delKeys)
  public abstract void replaceEntry(Entry oldEntry, Entry newEntry,
                                    Map<byte[], Boolean> modifiedKeys)
       throws DatabaseException;
  /**
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public abstract void modifyEntry(Transaction txn,
                                   Entry oldEntry, Entry newEntry,
  public abstract void modifyEntry(Entry oldEntry, Entry newEntry,
                                   List<Modification> mods,
                                   Set<byte[]> addKeys,
                                   Set<byte[]> delKeys)
                                   Map<byte[], Boolean> modifiedKeys)
       throws DatabaseException;
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
@@ -38,9 +38,6 @@
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseException;
import java.util.*;
/**
@@ -103,13 +100,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> keys)
  public void indexEntry(Entry entry, Set<byte[]> keys)
  {
    List<Attribute> attrList =
         entry.getAttribute(attributeType);
@@ -123,97 +117,38 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn,
                           Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(orderingRule);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(orderingRule);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
  /**
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
      throws DatabaseException
                          Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(orderingRule);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(orderingRule);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
@@ -262,4 +197,65 @@
    }
  }
  /**
   * Generate the set of index keys for an attribute.
   * @param attrList The attribute to be indexed.
   * @param modifiedKeys The map into which the modified
   * keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexAttribute(List<Attribute> attrList,
                              Map<byte[], Boolean> modifiedKeys,
                              Boolean insert)
  {
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      indexValues(attr.getValues(), modifiedKeys, insert);
    }
  }
  /**
   * Generate the set of index keys for a set of attribute values.
   * @param values The set of attribute values to be indexed.
   * @param modifiedKeys The map into which the modified
   *  keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexValues(Set<AttributeValue> values,
                           Map<byte[], Boolean> modifiedKeys,
                           Boolean insert)
  {
    if (values == null) return;
    for (AttributeValue value : values)
    {
      try
      {
        byte[] keyBytes =
             orderingRule.normalizeValue(value.getValue()).value();
        Boolean cInsert = modifiedKeys.get(keyBytes);
        if(cInsert == null)
        {
          modifiedKeys.put(keyBytes, insert);
        }
        else if(!cInsert.equals(insert))
        {
          modifiedKeys.remove(keyBytes);
        }
      }
      catch (DirectoryException e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java
@@ -31,12 +31,10 @@
import org.opends.server.types.Modification;
import org.opends.server.types.AttributeType;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.DatabaseException;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.Map;
/**
 * An implementation of an Indexer for attribute presence.
@@ -92,14 +90,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> keys) throws DatabaseException
  public void indexEntry(Entry entry,  Set<byte[]> keys)
  {
    List<Attribute> attrList =
         entry.getAttribute(attributeType);
@@ -118,18 +112,12 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn, Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
      throws DatabaseException
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
@@ -137,14 +125,14 @@
    {
      if(newAttributes != null)
      {
        addKeys.add(AttributeIndex.presenceKey.getData());
        modifiedKeys.put(AttributeIndex.presenceKey.getData(), true);
      }
    }
    else
    {
      if(newAttributes == null)
      {
        delKeys.add(AttributeIndex.presenceKey.getData());
        modifiedKeys.put(AttributeIndex.presenceKey.getData(), false);
      }
    }
  }
@@ -155,20 +143,14 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @throws DatabaseException If an error occurs in the JE database.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
       throws DatabaseException
                          Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
@@ -176,14 +158,14 @@
    {
      if(newAttributes != null)
      {
        addKeys.add(AttributeIndex.presenceKey.getData());
        modifiedKeys.put(AttributeIndex.presenceKey.getData(), true);
      }
    }
    else
    {
      if(newAttributes == null)
      {
        delKeys.add(AttributeIndex.presenceKey.getData());
        modifiedKeys.put(AttributeIndex.presenceKey.getData(), false);
      }
    }
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
@@ -28,7 +28,6 @@
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import com.sleepycat.je.Transaction;
import org.opends.server.types.*;
import java.util.*;
@@ -98,13 +97,10 @@
  /**
   * Generate the set of index keys for an entry.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   */
  public void indexEntry(Transaction txn, Entry entry,
                       Set<byte[]> keys)
  public void indexEntry(Entry entry, Set<byte[]> keys)
  {
    List<Attribute> attrList =
         entry.getAttribute(attributeType);
@@ -118,47 +114,18 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that has been replaced.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void replaceEntry(Transaction txn,
                           Entry oldEntry, Entry newEntry,
                           Set<byte[]> addKeys,
                           Set<byte[]> delKeys)
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
@@ -167,48 +134,20 @@
   * Generate the set of index keys to be added and the set of index keys
   * to be deleted for an entry that was modified.
   *
   * @param txn A database transaction to be used if the database need to be
   * accessed in the course of generating the index keys.
   * @param oldEntry The original entry contents.
   * @param newEntry The new entry contents.
   * @param mods The set of modifications that were applied to the entry.
   * @param addKeys The set into which the keys to be added will be inserted.
   * @param delKeys The set into which the keys to be deleted will be inserted.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  public void modifyEntry(Transaction txn, Entry oldEntry, Entry newEntry,
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Set<byte[]> addKeys,
                          Set<byte[]> delKeys)
                          Map<byte[], Boolean> modifiedKeys)
  {
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        TreeSet<byte[]> newKeys =
            new TreeSet<byte[]>(comparator);
        TreeSet<byte[]> oldKeys =
            new TreeSet<byte[]>(comparator);
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
    indexAttribute(oldAttributes, modifiedKeys, false);
    indexAttribute(newAttributes, modifiedKeys, true);
  }
@@ -299,4 +238,94 @@
    return keyBytes;
  }
  /**
   * Generate the set of index keys for an attribute.
   * @param attrList The attribute to be indexed.
   * @param modifiedKeys The map into which the modified
   * keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexAttribute(List<Attribute> attrList,
                              Map<byte[], Boolean> modifiedKeys,
                              Boolean insert)
  {
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      indexValues(attr.getValues(), modifiedKeys, insert);
    }
  }
  /**
   * Generate the set of index keys for a set of attribute values.
   * @param values The set of attribute values to be indexed.
   * @param modifiedKeys The map into which the modified
   *  keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void indexValues(Set<AttributeValue> values,
                           Map<byte[], Boolean> modifiedKeys,
                           Boolean insert)
  {
    if (values == null) return;
    for (AttributeValue value : values)
    {
      try
      {
        byte[] normalizedBytes = value.getNormalizedValue().value();
        substringKeys(normalizedBytes, modifiedKeys, insert);
      }
      catch (DirectoryException e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
  /**
   * Decompose an attribute value into a set of substring index keys.
   * The ID of the entry containing this value should be inserted
   * into the list of each of these keys.
   *
   * @param value A byte array containing the normalized attribute value
   * @param modifiedKeys The map into which the modified
   *  keys will be inserted.
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void substringKeys(byte[] value,
                             Map<byte[], Boolean> modifiedKeys,
                             Boolean insert)
  {
    byte[] keyBytes;
    // Example: The value is ABCDE and the substring length is 3.
    // We produce the keys ABC BCD CDE DE E
    // To find values containing a short substring such as DE,
    // iterate through keys with prefix DE. To find values
    // containing a longer substring such as BCDE, read keys
    // BCD and CDE.
    for (int i = 0, remain = value.length; remain > 0; i++, remain--)
    {
      int len = Math.min(substrLength, remain);
      keyBytes = makeSubstringKey(value, i, len);
      Boolean cInsert = modifiedKeys.get(keyBytes);
      if(cInsert == null)
      {
        modifiedKeys.put(keyBytes, insert);
      }
      else if(!cInsert.equals(insert))
      {
        modifiedKeys.remove(keyBytes);
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/BufferManager.java
@@ -102,7 +102,7 @@
          throws DatabaseException {
    Set<byte[]> keySet = new HashSet<byte[]>();
    index.indexer.indexEntry(txn, entry, keySet);
    index.indexer.indexEntry(entry, keySet);
    synchronized(elementMap) {
      insertKeySet(keySet, index, entryID);
      //If over the memory limit and import hasn't completed
@@ -127,9 +127,9 @@
  void insert(Index id2children, Index id2subtree, Entry entry,
         EntryID entryID, Transaction txn) throws DatabaseException {
    Set<byte[]> childKeySet = new HashSet<byte[]>();
    id2children.indexer.indexEntry(txn, entry, childKeySet);
    id2children.indexer.indexEntry(entry, childKeySet);
    Set<byte[]> subKeySet = new HashSet<byte[]>();
    id2subtree.indexer.indexEntry(txn, entry, subKeySet);
    id2subtree.indexer.indexEntry(entry, subKeySet);
     synchronized(elementMap) {
      insertKeySet(childKeySet, id2children, entryID);
      insertKeySet(subKeySet, id2subtree, entryID);
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java
@@ -289,7 +289,7 @@
  insert(Index index, Entry entry, EntryID entryID,
         Transaction txn) throws DatabaseException {
    Set<byte[]> keySet = new HashSet<byte[]>();
    index.indexer.indexEntry(txn, entry, keySet);
    index.indexer.indexEntry(entry, keySet);
    return index.insert(txn, keySet,  entryID);
  }
@@ -307,7 +307,7 @@
  delete(Index index, Entry entry, EntryID entryID,
         Transaction txn) throws DatabaseException {
    Set<byte[]> keySet = new HashSet<byte[]>();
    index.indexer.indexEntry(txn, entry, keySet);
    index.indexer.indexEntry(entry, keySet);
    index.delete(txn, keySet,  entryID);
  }
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -845,7 +845,7 @@
      addKeys = new HashSet<byte[]>();
      presenceIndexer = new PresenceIndexer(index.getAttributeType());
      presenceIndexer.indexEntry(null, entry, addKeys);
      presenceIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -856,7 +856,7 @@
      addKeys = new HashSet<byte[]>();
      equalityIndexer = new EqualityIndexer(index.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      equalityIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -868,7 +868,7 @@
      addKeys = new HashSet<byte[]>();
      substringIndexer = new SubstringIndexer(index.getAttributeType(),
                   index.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      substringIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -879,7 +879,7 @@
      addKeys = new HashSet<byte[]>();
      orderingIndexer = new OrderingIndexer(index.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      orderingIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -945,7 +945,7 @@
      addKeys = new HashSet<byte[]>();
      orderingIndexer = new OrderingIndexer(index.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      orderingIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -955,7 +955,7 @@
          ConditionResult.TRUE);
      addKeys = new HashSet<byte[]>();
      orderingIndexer.indexEntry(null, oldEntry, addKeys);
      orderingIndexer.indexEntry(oldEntry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -967,7 +967,7 @@
      addKeys = new HashSet<byte[]>();
      substringIndexer = new SubstringIndexer(index.getAttributeType(),
                                              index.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      substringIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -977,7 +977,7 @@
                   ConditionResult.TRUE);
      addKeys = new HashSet<byte[]>();
      substringIndexer.indexEntry(null, oldEntry, addKeys);
      substringIndexer.indexEntry(oldEntry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -988,7 +988,7 @@
      addKeys = new HashSet<byte[]>();
      equalityIndexer = new EqualityIndexer(index.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      equalityIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -998,7 +998,7 @@
          ConditionResult.TRUE);
      addKeys = new HashSet<byte[]>();
      equalityIndexer.indexEntry(null, oldEntry, addKeys);
      equalityIndexer.indexEntry(oldEntry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1178,7 +1178,7 @@
      addKeys = new HashSet<byte[]>();
      presenceIndexer = new PresenceIndexer(titleIndex.getAttributeType());
      presenceIndexer.indexEntry(null, entry, addKeys);
      presenceIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1189,7 +1189,7 @@
      addKeys = new HashSet<byte[]>();
      presenceIndexer = new PresenceIndexer(nameIndex.getAttributeType());
      presenceIndexer.indexEntry(null, entry, addKeys);
      presenceIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1200,7 +1200,7 @@
      addKeys = new HashSet<byte[]>();
      orderingIndexer = new OrderingIndexer(titleIndex.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      orderingIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1211,7 +1211,7 @@
      addKeys = new HashSet<byte[]>();
      orderingIndexer = new OrderingIndexer(nameIndex.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      orderingIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1222,7 +1222,7 @@
      addKeys = new HashSet<byte[]>();
      equalityIndexer = new EqualityIndexer(titleIndex.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      equalityIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1233,7 +1233,7 @@
      addKeys = new HashSet<byte[]>();
      equalityIndexer = new EqualityIndexer(nameIndex.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      equalityIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1245,7 +1245,7 @@
      addKeys = new HashSet<byte[]>();
      substringIndexer = new SubstringIndexer(titleIndex.getAttributeType(),
                   titleIndex.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      substringIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {
@@ -1257,7 +1257,7 @@
      addKeys = new HashSet<byte[]>();
      substringIndexer = new SubstringIndexer(nameIndex.getAttributeType(),
                   nameIndex.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      substringIndexer.indexEntry(entry, addKeys);
      key = new DatabaseEntry();
      for (byte[] keyBytes : addKeys) {