From 88f8db26c1a4389ea8ddcd5679f433446d0a55f3 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 08 Oct 2015 09:59:03 +0000
Subject: [PATCH] OPENDJ-1852 Fix feature envy between AttributeIndex and Index* classes

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/IndexQueryFactoryImpl.java |  119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 115 insertions(+), 4 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/IndexQueryFactoryImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/IndexQueryFactoryImpl.java
index 16e6ddc..9397e00 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/IndexQueryFactoryImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/IndexQueryFactoryImpl.java
@@ -27,8 +27,8 @@
 package org.opends.server.backends.pluggable;
 
 import static org.opends.messages.BackendMessages.*;
-import static org.opends.server.backends.pluggable.EntryIDSet.newUndefinedSet;
-import static org.opends.server.backends.pluggable.EntryIDSet.newUndefinedSetWithKey;
+import static org.opends.server.backends.pluggable.EntryIDSet.*;
+import static org.opends.server.backends.pluggable.IndexFilter.*;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -39,6 +39,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
 import org.forgerock.opendj.ldap.spi.IndexingOptions;
+import org.forgerock.util.Utils;
 import org.opends.server.backends.pluggable.AttributeIndex.IndexFilterType;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.ReadableTransaction;
@@ -50,9 +51,109 @@
  */
 final class IndexQueryFactoryImpl implements IndexQueryFactory<IndexQuery>
 {
+  /**
+   * This class creates a Null IndexQuery. It is used when there is no
+   * record in the index. It may also be used when the index contains
+   * all the records but an empty EntryIDSet should be returned as part
+   * of the optimization.
+   */
+  private static final class NullIndexQuery implements IndexQuery
+  {
+    @Override
+    public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage, StringBuilder indexNameOut)
+    {
+      return newUndefinedSet();
+    }
+
+    @Override
+    public String toString()
+    {
+      return "Null";
+    }
+  }
+
+  /** This class creates an intersection IndexQuery from a collection of IndexQuery objects. */
+  private static final class IntersectionIndexQuery implements IndexQuery
+  {
+    /** Collection of IndexQuery objects. */
+    private final Collection<IndexQuery> subIndexQueries;
+
+    /**
+     * Creates an instance of IntersectionIndexQuery.
+     *
+     * @param subIndexQueries
+     *          Collection of IndexQuery objects.
+     */
+    private IntersectionIndexQuery(Collection<IndexQuery> subIndexQueries)
+    {
+      this.subIndexQueries = subIndexQueries;
+    }
+
+    @Override
+    public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage, StringBuilder indexNameOut)
+    {
+      final EntryIDSet entryIDs = newUndefinedSet();
+      for (IndexQuery query : subIndexQueries)
+      {
+        entryIDs.retainAll(query.evaluate(debugMessage, indexNameOut));
+        if (isBelowFilterThreshold(entryIDs))
+        {
+          break;
+        }
+      }
+      return entryIDs;
+    }
+
+    @Override
+    public String toString()
+    {
+      return "Intersection(" + SEPARATOR + Utils.joinAsString(SEPARATOR, subIndexQueries) + ")";
+    }
+  }
+
+  /** This class creates a union of IndexQuery objects. */
+  private static final class UnionIndexQuery implements IndexQuery
+  {
+    /** Collection containing IndexQuery objects. */
+    private final Collection<IndexQuery> subIndexQueries;
+
+    /**
+     * Creates an instance of UnionIndexQuery.
+     *
+     * @param subIndexQueries
+     *          The Collection of IndexQuery objects.
+     */
+    private UnionIndexQuery(Collection<IndexQuery> subIndexQueries)
+    {
+      this.subIndexQueries = subIndexQueries;
+    }
+
+    @Override
+    public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage, StringBuilder indexNameOut)
+    {
+      final EntryIDSet entryIDs = newDefinedSet();
+      for (IndexQuery query : subIndexQueries)
+      {
+        entryIDs.addAll(query.evaluate(debugMessage, indexNameOut));
+        if (entryIDs.isDefined() && entryIDs.size() >= CURSOR_ENTRY_LIMIT)
+        {
+          break;
+        }
+      }
+      return entryIDs;
+    }
+
+    @Override
+    public String toString()
+    {
+      return "Union(" + SEPARATOR + Utils.joinAsString(SEPARATOR, subIndexQueries) + ")";
+    }
+  }
+
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   private static final String PRESENCE_INDEX_KEY = "presence";
+  private static final String SEPARATOR = "\n  ";
 
   private final ReadableTransaction txn;
   /** The Map containing the string type identifier and the corresponding index. */
@@ -241,13 +342,13 @@
   @Override
   public IndexQuery createIntersectionQuery(Collection<IndexQuery> subqueries)
   {
-    return IndexQuery.createIntersectionIndexQuery(subqueries);
+    return new IntersectionIndexQuery(subqueries);
   }
 
   @Override
   public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries)
   {
-    return IndexQuery.createUnionIndexQuery(subqueries);
+    return new UnionIndexQuery(subqueries);
   }
 
   /**
@@ -313,4 +414,14 @@
   {
     return attributeIndex.getIndexingOptions();
   }
+
+  /**
+   * Creates an empty IndexQuery object.
+   *
+   * @return A NullIndexQuery object.
+   */
+  static IndexQuery createNullIndexQuery()
+  {
+    return new NullIndexQuery();
+  }
 }

--
Gitblit v1.10.0