From ff1493a5266895521add7ccc8e987369ee10b907 Mon Sep 17 00:00:00 2001
From: coulbeck <coulbeck@localhost>
Date: Fri, 08 Dec 2006 23:47:17 +0000
Subject: [PATCH] Fix for issues 593, 1045 and 1060.

---
 opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java |  153 ++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 110 insertions(+), 43 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
index e01051b..6388ced 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -43,6 +43,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.ArrayList;
 
 /**
  * An implementation of an Indexer for attribute equality.
@@ -112,7 +113,7 @@
    * @throws DatabaseException If an error occurs in the JE database.
    */
   public void indexEntry(Transaction txn, Entry entry,
-                       Set<ASN1OctetString> keys) throws DatabaseException
+                         Set<ASN1OctetString> keys) throws DatabaseException
   {
     List<Attribute> attrList =
          entry.getAttribute(indexConfig.getAttributeType());
@@ -188,76 +189,142 @@
                           Set<ASN1OctetString> delKeys)
        throws DatabaseException
   {
+    // Optimize for the case where there are no attribute options
+    // involved and only simple addition and deletion of individual values.
+    // An issue with attribute options is that the values can not be assumed
+    // to be unique.
+
     List<Attribute> beforeList;
+    List<Attribute> afterList;
     beforeList = oldEntry.getAttribute(indexConfig.getAttributeType());
+    afterList = newEntry.getAttribute(indexConfig.getAttributeType());
 
-    // Pick out the modifications that apply to this indexed attribute
+    boolean hasOptions = false;
 
-    /**
-     * FIXME unusual modifications can insert spurious index values
-     * The following sequence of modifications will insert A into the
-     * index, yet A is not a resulting value for the attribute.
-     *
-     * add: cn
-     * cn: A
-     * -
-     * replace: cn
-     * cn: B
-     * -
-     *
-     */
+    if (beforeList != null)
+    {
+      for (Attribute a : beforeList)
+      {
+        if (a.hasOptions())
+        {
+          hasOptions = true;
+          break;
+        }
+      }
+    }
 
+    if (afterList != null)
+    {
+      for (Attribute a : afterList)
+      {
+        if (a.hasOptions())
+        {
+          hasOptions = true;
+          break;
+        }
+      }
+    }
+
+    boolean hasOnlySimpleMods = true;
+    List<Modification> simpleMods = new ArrayList<Modification>();
     for (Modification mod : mods)
     {
       Attribute modAttr = mod.getAttribute();
       AttributeType modAttrType = modAttr.getAttributeType();
       if (modAttrType.equals(indexConfig.getAttributeType()))
       {
+        if (modAttr.hasOptions())
+        {
+          hasOptions = true;
+        }
         switch (mod.getModificationType())
         {
-          case REPLACE:
-          case INCREMENT:
-            if (beforeList != null)
-            {
-              for (Attribute attr : beforeList)
-              {
-                if (attr.hasOptions(modAttr.getOptions()))
-                {
-                  indexValues(attr.getValues(), delKeys);
-                }
-              }
-            }
-            indexValues(modAttr.getValues(), addKeys);
-            break;
-
           case ADD:
-            indexValues(modAttr.getValues(), addKeys);
+            simpleMods.add(mod);
             break;
 
           case DELETE:
             if (!modAttr.hasValue())
             {
-              if (beforeList != null)
-              {
-                for (Attribute attr : beforeList)
-                {
-                  if (attr.hasOptions(modAttr.getOptions()))
-                  {
-                    indexValues(attr.getValues(), delKeys);
-                  }
-                }
-              }
+              hasOnlySimpleMods = false;
             }
             else
             {
-              indexValues(modAttr.getValues(), delKeys);
+              simpleMods.add(mod);
+            }
+            break;
+
+          default:
+            hasOnlySimpleMods = false;
+            break;
+        }
+      }
+    }
+
+    if (hasOnlySimpleMods && !hasOptions)
+    {
+      // This is the optimized case where there are no attribute options
+      // involved and only simple addition and deletion of individual values.
+      // It should be efficient for adding and/or deleting a few values of an
+      // attribute with lots of values.
+      for (Modification mod : simpleMods)
+      {
+        Set<AttributeValue> values = mod.getAttribute().getValues();
+        Set<ASN1OctetString> keys =
+             new HashSet<ASN1OctetString>(values.size());
+        indexValues(values, keys);
+
+        switch (mod.getModificationType())
+        {
+          case ADD:
+            for (ASN1OctetString key : keys)
+            {
+              if (delKeys.contains(key))
+              {
+                delKeys.remove(key);
+              }
+              else
+              {
+                addKeys.add(key);
+              }
+            }
+            break;
+
+          case DELETE:
+            for (ASN1OctetString key : keys)
+            {
+              if (addKeys.contains(key))
+              {
+                addKeys.remove(key);
+              }
+              else
+              {
+                delKeys.add(key);
+              }
             }
             break;
         }
       }
     }
-  }
+    else
+    {
+      // This is the non-optimized case that should be correct in all cases.
 
+      Set<ASN1OctetString> oldSet = new HashSet<ASN1OctetString>();
+      indexAttribute(beforeList, oldSet);
+
+      Set<ASN1OctetString> newSet = new HashSet<ASN1OctetString>();
+      indexAttribute(afterList, newSet);
+
+      HashSet<ASN1OctetString> removeSet = new HashSet<ASN1OctetString>(oldSet);
+      removeSet.removeAll(newSet);
+      delKeys.addAll(removeSet);
+
+      HashSet<ASN1OctetString> addSet = new HashSet<ASN1OctetString>(newSet);
+      addSet.removeAll(oldSet);
+      addKeys.addAll(addSet);
+    }
+  }
 
   /**
    * Generate the set of index keys for a set of attribute values.

--
Gitblit v1.10.0