From db63ffab5595ce0298f2cc306d9d1d30804be283 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 26 Jan 2012 14:14:28 +0000
Subject: [PATCH] Fix OPENDJ-413: verify-index with "-c" option doesn't work for certain indexes

---
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java |  191 ++++++++++-------------------------------------
 1 files changed, 43 insertions(+), 148 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
index bc53658..3b14ff9 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VerifyJob.java
@@ -23,7 +23,7 @@
  *
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
- *      Portions copyright 2011 ForgeRock AS
+ *      Portions copyright 2011-2012 ForgeRock AS
  */
 package org.opends.server.backends.jeb;
 import com.sleepycat.je.*;
@@ -44,15 +44,8 @@
 
 import static org.opends.messages.JebMessages.*;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This class is used to run an index verification process on the backend.
@@ -1013,7 +1006,6 @@
     try
     {
       DatabaseEntry key = new DatabaseEntry();
-      OperationStatus status;
       DatabaseEntry data = new DatabaseEntry();
 
       SortValues lastValues = null;
@@ -1135,12 +1127,6 @@
       DatabaseEntry key = new DatabaseEntry();
       DatabaseEntry data = new DatabaseEntry();
 
-      OrderingMatchingRule orderingMatchingRule =
-          attrType.getOrderingMatchingRule();
-      ApproximateMatchingRule approximateMatchingRule =
-          attrType.getApproximateMatchingRule();
-      ByteString previousValue = null;
-
       while (cursor.getNext(key, data, null) ==
                 OperationStatus.SUCCESS)
       {
@@ -1170,97 +1156,9 @@
 
         if (entryIDList.isDefined())
         {
-          byte[] value = key.getData();
-          SearchFilter sf;
-          AttributeValue assertionValue;
-
-          switch (indexType)
-          {
-            case SUBSTRING:
-              ArrayList<ByteString> subAnyElements =
-                   new ArrayList<ByteString>(1);
-              subAnyElements.add(ByteString.wrap(value));
-
-              sf = SearchFilter.createSubstringFilter(attrType,null,
-                                                      subAnyElements,null);
-              break;
-            case ORDERING:
-              // Ordering index checking is two fold:
-              // 1. Make sure the entry has an attribute value that is the same
-              //    as the key. This is done by falling through to the next
-              //    case and create an equality filter.
-              // 2. Make sure the key value is greater then the previous key
-              //    value.
-              assertionValue =
-                  AttributeValues.create(attrType,
-                      ByteString.wrap(value));
-
-              sf = SearchFilter.createEqualityFilter(attrType,assertionValue);
-
-              if(orderingMatchingRule != null && previousValue != null)
-              {
-                ByteString thisValue = ByteString.wrap(value);
-                int order = orderingMatchingRule.compareValues(thisValue,
-                                                               previousValue);
-                if(order > 0)
-                {
-                  errorCount++;
-                  if(debugEnabled())
-                  {
-                    TRACER.debugError("Reversed ordering of index keys " +
-                        "(keys dumped in the order found in database)%n" +
-                        "Key 1:%n%s%nKey 2:%n%s",
-                               keyDump(index, thisValue.toByteArray()),
-                               keyDump(index,previousValue.toByteArray()));
-                  }
-                  continue;
-                }
-                else if(order == 0)
-                {
-                  errorCount++;
-                  if(debugEnabled())
-                  {
-                    TRACER.debugError("Duplicate index keys%nKey 1:%n%s%n" +
-                        "Key2:%n%s", keyDump(index, thisValue.toByteArray()),
-                                     keyDump(index,
-                                         previousValue.toByteArray()));
-                  }
-                  continue;
-                }
-                else
-                {
-                  previousValue = thisValue;
-                }
-              }
-              break;
-            case EQ:
-              assertionValue =
-                  AttributeValues.create(attrType,
-                      ByteString.wrap(value));
-
-              sf = SearchFilter.createEqualityFilter(attrType,assertionValue);
-              break;
-
-            case PRES:
-              sf = SearchFilter.createPresenceFilter(attrType);
-              break;
-
-            case APPROXIMATE:
-              // This must be handled differently since we can't use a search
-              // filter to see if the key matches.
-              sf = null;
-              break;
-
-            default:
-              errorCount++;
-              if (debugEnabled())
-              {
-                TRACER.debugError("Malformed value%n%s", keyDump(index, value));
-              }
-              continue;
-          }
-
+          final byte[] value = key.getData();
           EntryID prevID = null;
+
           for (EntryID id : entryIDList)
           {
             if (prevID != null && id.equals(prevID))
@@ -1299,56 +1197,53 @@
               continue;
             }
 
-            try
+            // As an optimization avoid passing in a real set and wasting time
+            // hashing and comparing a potentially large set of values, as well
+            // as using up memory. Instead just intercept the add() method and
+            // detect when an equivalent value has been added.
+
+            // We need to use an AtomicBoolean here since anonymous classes
+            // require referenced external variables to be final.
+            final AtomicBoolean foundMatchingKey = new AtomicBoolean(false);
+
+            Set<byte[]> dummySet = new AbstractSet<byte[]>()
             {
-              boolean match = false;
-              if(indexType != IndexType.APPROXIMATE)
+
+              public Iterator<byte[]> iterator()
               {
-                match = sf.matchesEntry(entry);
-              }
-              else
-              {
-                ByteString normalizedValue = ByteString.wrap(value);
-                List<Attribute> attrs = entry.getAttribute(attrType);
-                if ((attrs != null) && (!attrs.isEmpty()))
-                {
-                  for (Attribute a : attrs)
-                  {
-                    for (AttributeValue v : a)
-                    {
-                      ByteString nv =
-                          approximateMatchingRule.normalizeValue(v.getValue());
-                      match = approximateMatchingRule.
-                          approximatelyMatch(nv, normalizedValue);
-                      if(match)
-                      {
-                        break;
-                      }
-                    }
-                    if(match)
-                    {
-                      break;
-                    }
-                  }
-                }
+                // The set is always empty.
+                return Collections.<byte[]>emptySet().iterator();
               }
 
-              if (!match)
+              public int size()
               {
-                errorCount++;
-                if (debugEnabled())
-                {
-                  TRACER.debugError("Reference to entry " +
-                      "<%s> which does not match the value%n%s",
-                             entry.getDN(), keyDump(index, value));
-                }
+                // The set is always empty.
+                return 0;
               }
-            }
-            catch (DirectoryException e)
+
+              public boolean add(byte[] e)
+              {
+                if (Arrays.equals(e, value)) {
+                  // We could terminate processing at this point by throwing an
+                  // UnsupportedOperationException, but this optimization is
+                  // already ugly enough.
+                  foundMatchingKey.set(true);
+                }
+                return true;
+              }
+
+            };
+
+            index.indexer.indexEntry(entry, dummySet);
+
+            if (!foundMatchingKey.get())
             {
+              errorCount++;
               if (debugEnabled())
               {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+                TRACER.debugError("Reference to entry "
+                    + "<%s> which does not match the value%n%s", entry.getDN(),
+                    keyDump(index, value));
               }
             }
           }

--
Gitblit v1.10.0