You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by is...@apache.org on 2024/02/05 19:47:08 UTC

(solr) 02/02: SOLR-13350: Fix tests and precommit

This is an automated email from the ASF dual-hosted git repository.

ishan pushed a commit to branch jira/solr-13350
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 74c05e520abe85f056fe440976dbbd6a812b6386
Author: Ishan Chattopadhyaya <is...@apache.org>
AuthorDate: Tue May 23 03:21:59 2023 +0530

    SOLR-13350: Fix tests and precommit
---
 .../java/org/apache/solr/core/CoreContainer.java   |  13 +-
 .../java/org/apache/solr/search/QueryResult.java   |   2 +-
 .../org/apache/solr/search/SolrIndexSearcher.java  | 344 +++++-----
 .../solr/search/SolrMultiCollectorManager.java     |  27 +-
 .../org/apache/solr/search/ThreadSafeBitSet.java   | 714 +++++++++++----------
 .../solr/search/ThreadSafeBitSetCollector.java     |  31 +-
 .../org/apache/solr/TestDistributedSearch.java     |   2 +-
 .../test/org/apache/solr/search/TestFiltering.java |  21 +-
 8 files changed, 603 insertions(+), 551 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 012c31633b8..9146177e2b1 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -177,11 +177,11 @@ public class CoreContainer {
 
   final SolrCores solrCores;
 
-    public Executor getCollectorExecutor() {
-      return collectorExecutor;
-    }
+  public Executor getCollectorExecutor() {
+    return collectorExecutor;
+  }
 
-    public static class CoreLoadFailure {
+  public static class CoreLoadFailure {
 
     public final CoreDescriptor cd;
     public final Exception exception;
@@ -440,8 +440,9 @@ public class CoreContainer {
 
     this.allowListUrlChecker = AllowListUrlChecker.create(config);
 
-    this.collectorExecutor = ExecutorUtil.newMDCAwareCachedThreadPool(6,
-        new SolrNamedThreadFactory("searcherCollector"));
+    this.collectorExecutor =
+        ExecutorUtil.newMDCAwareCachedThreadPool(
+            6, new SolrNamedThreadFactory("searcherCollector"));
   }
 
   @SuppressWarnings({"unchecked"})
diff --git a/solr/core/src/java/org/apache/solr/search/QueryResult.java b/solr/core/src/java/org/apache/solr/search/QueryResult.java
index 5d4500a4878..25399cb336c 100755
--- a/solr/core/src/java/org/apache/solr/search/QueryResult.java
+++ b/solr/core/src/java/org/apache/solr/search/QueryResult.java
@@ -46,7 +46,7 @@ public class QueryResult {
       docListAndSet = new DocListAndSet();
     }
     docListAndSet.docSet = set;
-   // log.error("set docset {}",     docListAndSet.docSet.getBits().length());
+    // log.error("set docset {}",     docListAndSet.docSet.getBits().length());
   }
 
   public boolean isPartialResults() {
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index a8c11016848..23df0a8b296 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -1873,46 +1873,53 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       qr.setNextCursorMark(cmd.getCursorMark());
       hitsRelation = Relation.EQUAL_TO;
     } else {
-      log.info("calling from 2, query: "+query.getClass()); // nocommit
+      if (log.isInfoEnabled()) {
+        log.info("calling from 2, query: {}", query.getClass());
+      }
       MTCollectorQueryCheck allowMT = new MTCollectorQueryCheck();
       query.visit(allowMT);
       TopDocs topDocs;
-      if (pf.postFilter != null || cmd.getSegmentTerminateEarly() || cmd.getTimeAllowed() > 0
-              || !allowMT.allowed()) {
-        log.debug("skipping collector manager");
-      final TopDocsCollector<?> topCollector = buildTopDocsCollector(len, cmd);
-      MaxScoreCollector maxScoreCollector = null;
-      Collector collector = topCollector;
-      if (needScores) {
-        maxScoreCollector = new MaxScoreCollector();
-        collector = MultiCollector.wrap(topCollector, maxScoreCollector);
-      }
-      ScoreMode scoreModeUsed =
-          buildAndRunCollectorChain(qr, query, collector, cmd, pf.postFilter).scoreMode();
+      if (pf.postFilter != null
+          || cmd.getSegmentTerminateEarly()
+          || cmd.getTimeAllowed() > 0
+          || !allowMT.allowed()) {
+        if (log.isInfoEnabled()) {
+          log.info("skipping collector manager");
+        }
+        final TopDocsCollector<?> topCollector = buildTopDocsCollector(len, cmd);
+        MaxScoreCollector maxScoreCollector = null;
+        Collector collector = topCollector;
+        if (needScores) {
+          maxScoreCollector = new MaxScoreCollector();
+          collector = MultiCollector.wrap(topCollector, maxScoreCollector);
+        }
+        ScoreMode scoreModeUsed =
+            buildAndRunCollectorChain(qr, query, collector, cmd, pf.postFilter).scoreMode();
 
-      totalHits = topCollector.getTotalHits();
-      topDocs = topCollector.topDocs(0, len);
-      if (scoreModeUsed == ScoreMode.COMPLETE || scoreModeUsed == ScoreMode.COMPLETE_NO_SCORES) {
-        hitsRelation = TotalHits.Relation.EQUAL_TO;
-      } else {
-        hitsRelation = topDocs.totalHits.relation;
-      }
-      if (cmd.getSort() != null
-          && cmd.getQuery() instanceof RankQuery == false
-          && needScores) {
-        TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
-      }
-      populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
+        totalHits = topCollector.getTotalHits();
+        topDocs = topCollector.topDocs(0, len);
+        if (scoreModeUsed == ScoreMode.COMPLETE || scoreModeUsed == ScoreMode.COMPLETE_NO_SCORES) {
+          hitsRelation = TotalHits.Relation.EQUAL_TO;
+        } else {
+          hitsRelation = topDocs.totalHits.relation;
+        }
+        if (cmd.getSort() != null && cmd.getQuery() instanceof RankQuery == false && needScores) {
+          TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+        }
+        populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
 
-      maxScore =
-          totalHits > 0
-              ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore())
-              : 0.0f;
-      nDocsReturned = topDocs.scoreDocs.length;
+        maxScore =
+            totalHits > 0
+                ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore())
+                : 0.0f;
+        nDocsReturned = topDocs.scoreDocs.length;
 
       } else {
-        log.info("using CollectorManager");
-        SearchResult searchResult = searchCollectorManagers(len, cmd, query, true, needScores, false);
+        if (log.isInfoEnabled()) {
+          log.info("using CollectorManager");
+        }
+        SearchResult searchResult =
+            searchCollectorManagers(len, cmd, query, true, needScores, false);
         Object[] res = searchResult.result;
         TopDocsResult result = (TopDocsResult) res[0];
 
@@ -1937,7 +1944,6 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
         } else {
           hitsRelation = topDocs.totalHits.relation;
         }
-
       }
 
       ids = new int[nDocsReturned];
@@ -1954,8 +1960,14 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
     qr.setDocList(new DocSlice(0, sliceLen, ids, scores, totalHits, maxScore, hitsRelation));
   }
 
-  SearchResult searchCollectorManagers(int len, QueryCommand cmd, Query query,
-                                       boolean needTopDocs, boolean needMaxScore, boolean needDocSet) throws IOException {
+  SearchResult searchCollectorManagers(
+      int len,
+      QueryCommand cmd,
+      Query query,
+      boolean needTopDocs,
+      boolean needMaxScore,
+      boolean needDocSet)
+      throws IOException {
     Collection<CollectorManager<Collector, Object>> collectors = new ArrayList<>();
     ScoreMode scoreMode = null;
 
@@ -1963,75 +1975,80 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
 
     if (needTopDocs) {
 
-      collectors.add(new CollectorManager<>() {
-        @Override
-        public Collector newCollector() throws IOException {
-          @SuppressWarnings("rawtypes")
-          TopDocsCollector collector = buildTopDocsCollector(len, cmd);
-          if (firstCollectors[0] == null) {
-            firstCollectors[0] = collector;
-          }
-          return collector;
-        }
+      collectors.add(
+          new CollectorManager<>() {
+            @Override
+            public Collector newCollector() throws IOException {
+              @SuppressWarnings("rawtypes")
+              TopDocsCollector collector = buildTopDocsCollector(len, cmd);
+              if (firstCollectors[0] == null) {
+                firstCollectors[0] = collector;
+              }
+              return collector;
+            }
 
-        @Override
-        @SuppressWarnings("rawtypes")
-        public Object reduce(Collection collectors) throws IOException {
+            @Override
+            @SuppressWarnings("rawtypes")
+            public Object reduce(Collection collectors) throws IOException {
 
-          TopDocs[] topDocs = new TopDocs[collectors.size()];
+              TopDocs[] topDocs = new TopDocs[collectors.size()];
 
-          int totalHits = -1;
-          int i = 0;
+              int totalHits = -1;
+              int i = 0;
 
-          Collector collector;
-          for (Object o : collectors) {
-            collector = (Collector) o;
-            if (collector instanceof TopDocsCollector) {
-              TopDocs td = ((TopDocsCollector) collector).topDocs(0, len);
-              assert td != null : Arrays.asList(topDocs);
-              topDocs[i++] = td;
-            }
-          }
+              Collector collector;
+              for (Object o : collectors) {
+                collector = (Collector) o;
+                if (collector instanceof TopDocsCollector) {
+                  TopDocs td = ((TopDocsCollector) collector).topDocs(0, len);
+                  assert td != null : Arrays.asList(topDocs);
+                  topDocs[i++] = td;
+                }
+              }
 
-          TopDocs mergedTopDocs = null;
+              TopDocs mergedTopDocs = null;
 
-          if (topDocs.length > 0 && topDocs[0] != null) {
-            if (topDocs[0] instanceof TopFieldDocs) {
-              TopFieldDocs[] topFieldDocs = Arrays.copyOf(topDocs, topDocs.length, TopFieldDocs[].class);
-              mergedTopDocs = TopFieldDocs.merge(weightSort(cmd.getSort()), len, topFieldDocs);
-            } else {
-              mergedTopDocs = TopDocs.merge(0, len, topDocs);
+              if (topDocs.length > 0 && topDocs[0] != null) {
+                if (topDocs[0] instanceof TopFieldDocs) {
+                  TopFieldDocs[] topFieldDocs =
+                      Arrays.copyOf(topDocs, topDocs.length, TopFieldDocs[].class);
+                  mergedTopDocs = TopFieldDocs.merge(weightSort(cmd.getSort()), len, topFieldDocs);
+                } else {
+                  mergedTopDocs = TopDocs.merge(0, len, topDocs);
+                }
+                totalHits = (int) mergedTopDocs.totalHits.value;
+              }
+              return new TopDocsResult(mergedTopDocs, totalHits);
             }
-            totalHits = (int) mergedTopDocs.totalHits.value;
-          }
-          return new TopDocsResult(mergedTopDocs, totalHits);
-        }
-      });
+          });
     }
     if (needMaxScore) {
-      collectors.add(new CollectorManager<>() {
-        @Override
-        public Collector newCollector() throws IOException {
-          MaxScoreCollector collector = new MaxScoreCollector();
-          if (firstCollectors[1] == null) {
-            firstCollectors[1] = collector;
-          }
-          return collector;
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        public Object reduce(Collection collectors) throws IOException {
+      collectors.add(
+          new CollectorManager<>() {
+            @Override
+            public Collector newCollector() throws IOException {
+              MaxScoreCollector collector = new MaxScoreCollector();
+              if (firstCollectors[1] == null) {
+                firstCollectors[1] = collector;
+              }
+              return collector;
+            }
 
-          MaxScoreCollector collector;
-          float maxScore = 0.0f;
-          for (Iterator var4 = collectors.iterator(); var4.hasNext(); maxScore = Math.max(maxScore, collector.getMaxScore())) {
-            collector = (MaxScoreCollector) var4.next();
-          }
+            @Override
+            @SuppressWarnings("rawtypes")
+            public Object reduce(Collection collectors) throws IOException {
+
+              MaxScoreCollector collector;
+              float maxScore = 0.0f;
+              for (Iterator var4 = collectors.iterator();
+                  var4.hasNext();
+                  maxScore = Math.max(maxScore, collector.getMaxScore())) {
+                collector = (MaxScoreCollector) var4.next();
+              }
 
-          return new MaxScoreResult(maxScore);
-        }
-      });
+              return new MaxScoreResult(maxScore);
+            }
+          });
     }
     if (needDocSet) {
       int maxDoc = rawReader.maxDoc();
@@ -2040,37 +2057,38 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       LeafSlice[] leaves = getSlices();
       int[] docBase = new int[1];
 
-   //   DocSetCollector collector = new DocSetCollector(maxDoc);
+      //   DocSetCollector collector = new DocSetCollector(maxDoc);
 
       ThreadSafeBitSet bits = new ThreadSafeBitSet(14, 2);
 
+      collectors.add(
+          new CollectorManager<>() {
+            @Override
+            public Collector newCollector() throws IOException {
+              int numDocs = 0;
 
-      collectors.add(new CollectorManager<>() {
-        @Override
-        public Collector newCollector() throws IOException {
-          int numDocs = 0;
+              if (leaves != null) {
+                LeafSlice leaf = leaves[docBase[0]++];
 
-          if (leaves != null) {
-            LeafSlice leaf = leaves[docBase[0]++];
+                for (LeafReaderContext reader : leaf.leaves) {
+                  numDocs += reader.reader().maxDoc();
+                }
+              } else {
+                numDocs = maxDoc();
+              }
+              log.error("new docset collector for {} max={}", numDocs, maxDoc());
 
-            for (LeafReaderContext reader : leaf.leaves) {
-              numDocs += reader.reader().maxDoc();
+              return new ThreadSafeBitSetCollector(bits, maxDoc);
             }
-          } else {
-            numDocs = maxDoc();
-          }
-          log.error("new docset collector for {} max={}", numDocs, maxDoc());
 
-          return new ThreadSafeBitSetCollector(bits, maxDoc);
-        }
-
-        @Override
-        @SuppressWarnings({"rawtypes"})
-        public Object reduce(Collection collectors) throws IOException {
+            @Override
+            @SuppressWarnings({"rawtypes"})
+            public Object reduce(Collection collectors) throws IOException {
 
-          return new DocSetResult(((ThreadSafeBitSetCollector)collectors.iterator().next()).getDocSet());
-        }
-      });
+              return new DocSetResult(
+                  ((ThreadSafeBitSetCollector) collectors.iterator().next()).getDocSet());
+            }
+          });
     }
     for (Collector collector : firstCollectors) {
       if (collector != null) {
@@ -2089,16 +2107,17 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
     try {
       ret = super.search(query, manager);
     } catch (Exception ex) {
-      if (ex instanceof RuntimeException &&
-              ex.getCause() != null & ex.getCause() instanceof ExecutionException
-              && ex.getCause().getCause() != null && ex.getCause().getCause() instanceof RuntimeException) {
+      if (ex instanceof RuntimeException
+          && ex.getCause() != null
+          && ex.getCause() instanceof ExecutionException
+          && ex.getCause().getCause() != null
+          && ex.getCause().getCause() instanceof RuntimeException) {
         throw (RuntimeException) ex.getCause().getCause();
       } else {
         throw ex;
       }
     }
-   
-    
+
     return new SearchResult(scoreMode, ret);
   }
 
@@ -2137,7 +2156,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       this.result = result;
     }
   }
-  
+
   // any DocSet returned is for the query only, without any filtering... that way it may
   // be cached if desired.
   private DocSet getDocListAndSetNC(QueryResult qr, QueryCommand cmd) throws IOException {
@@ -2210,44 +2229,47 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       MTCollectorQueryCheck allowMT = new MTCollectorQueryCheck();
       query.visit(allowMT);
       TopDocs topDocs;
-      if (pf.postFilter != null || cmd.getSegmentTerminateEarly() || cmd.getTimeAllowed() > 0
-              || !allowMT.allowed()) {
-      @SuppressWarnings({"rawtypes"})
-      final TopDocsCollector<? extends ScoreDoc> topCollector = buildTopDocsCollector(len, cmd);
-      DocSetCollector setCollector = new DocSetCollector(maxDoc);
-      MaxScoreCollector maxScoreCollector = null;
-      List<Collector> collectors = new ArrayList<>(Arrays.asList(topCollector, setCollector));
-
-      if ((cmd.getFlags() & GET_SCORES) != 0) {
-        maxScoreCollector = new MaxScoreCollector();
-        collectors.add(maxScoreCollector);
-      }
+      if (pf.postFilter != null
+          || cmd.getSegmentTerminateEarly()
+          || cmd.getTimeAllowed() > 0
+          || !allowMT.allowed()) {
+        @SuppressWarnings({"rawtypes"})
+        final TopDocsCollector<? extends ScoreDoc> topCollector = buildTopDocsCollector(len, cmd);
+        DocSetCollector setCollector = new DocSetCollector(maxDoc);
+        MaxScoreCollector maxScoreCollector = null;
+        List<Collector> collectors = new ArrayList<>(Arrays.asList(topCollector, setCollector));
+
+        if ((cmd.getFlags() & GET_SCORES) != 0) {
+          maxScoreCollector = new MaxScoreCollector();
+          collectors.add(maxScoreCollector);
+        }
 
-      Collector collector = MultiCollector.wrap(collectors);
+        Collector collector = MultiCollector.wrap(collectors);
 
-      buildAndRunCollectorChain(qr, query, collector, cmd, pf.postFilter);
+        buildAndRunCollectorChain(qr, query, collector, cmd, pf.postFilter);
 
-      set = DocSetUtil.getDocSet(setCollector, this);
+        set = DocSetUtil.getDocSet(setCollector, this);
 
-      totalHits = topCollector.getTotalHits();
-      assert (totalHits == set.size()) || qr.isPartialResults();
+        totalHits = topCollector.getTotalHits();
+        assert (totalHits == set.size()) || qr.isPartialResults();
 
-      topDocs = topCollector.topDocs(0, len);
-      if (cmd.getSort() != null
-          && !(cmd.getQuery() instanceof RankQuery)
-          && (cmd.getFlags() & GET_SCORES) != 0) {
-        TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
-      }
-      populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
-      maxScore =
-          totalHits > 0
-              ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore())
-              : 0.0f;
+        topDocs = topCollector.topDocs(0, len);
+        if (cmd.getSort() != null
+            && !(cmd.getQuery() instanceof RankQuery)
+            && (cmd.getFlags() & GET_SCORES) != 0) {
+          TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+        }
+        populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
+        maxScore =
+            totalHits > 0
+                ? (maxScoreCollector == null ? Float.NaN : maxScoreCollector.getMaxScore())
+                : 0.0f;
       } else {
         log.debug("using CollectorManager");
 
         boolean needMaxScore = (cmd.getFlags() & GET_SCORES) != 0;
-        SearchResult searchResult = searchCollectorManagers(len, cmd, query, true, needMaxScore, true);
+        SearchResult searchResult =
+            searchCollectorManagers(len, cmd, query, true, needMaxScore, true);
         Object[] res = searchResult.result;
         TopDocsResult result = (TopDocsResult) res[0];
         totalHits = result.totalHits;
@@ -2269,12 +2291,13 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
         }
 
         populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
-//        if (cmd.getSort() != null && !(cmd.getQuery() instanceof RankQuery) && (cmd.getFlags() & GET_SCORES) != 0) {
-//          TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
-//        }
-       // nDocsReturned = topDocs.scoreDocs.length;
-        //TODO: Is this correct?
-        //hitsRelation = topDocs.totalHits.relation;
+        //        if (cmd.getSort() != null && !(cmd.getQuery() instanceof RankQuery) &&
+        // (cmd.getFlags() & GET_SCORES) != 0) {
+        //          TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
+        //        }
+        // nDocsReturned = topDocs.scoreDocs.length;
+        // TODO: Is this correct?
+        // hitsRelation = topDocs.totalHits.relation;
         //   } else {
         //    hitsRelation = Relation.EQUAL_TO;
         //   }
@@ -2905,14 +2928,16 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       return true;
     }
 
+    @Override
     public void consumeTerms(Query query, Term... terms) {
       if (!allowMt(query)) {
         subVisitor = EMPTY_VISITOR;
       }
     }
 
+    @Override
     public void consumeTermsMatching(
-            Query query, String field, Supplier<ByteRunAutomaton> automaton) {
+        Query query, String field, Supplier<ByteRunAutomaton> automaton) {
       if (!allowMt(query)) {
         subVisitor = EMPTY_VISITOR;
       } else {
@@ -2920,12 +2945,14 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       }
     }
 
+    @Override
     public void visitLeaf(Query query) {
       if (!allowMt(query)) {
         subVisitor = EMPTY_VISITOR;
       }
     }
 
+    @Override
     public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) {
       return subVisitor;
     }
@@ -2934,5 +2961,4 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       return subVisitor != EMPTY_VISITOR;
     }
   }
-
 }
diff --git a/solr/core/src/java/org/apache/solr/search/SolrMultiCollectorManager.java b/solr/core/src/java/org/apache/solr/search/SolrMultiCollectorManager.java
index 0af33da4a63..df44db8d337 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrMultiCollectorManager.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrMultiCollectorManager.java
@@ -21,7 +21,13 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.*;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.CollectorManager;
+import org.apache.lucene.search.FilterScorable;
+import org.apache.lucene.search.LeafCollector;
+import org.apache.lucene.search.MultiCollector;
+import org.apache.lucene.search.Scorable;
+import org.apache.lucene.search.ScoreMode;
 
 /**
  * A {@link CollectorManager} implements which wrap a set of {@link CollectorManager} as {@link
@@ -100,7 +106,8 @@ public class SolrMultiCollectorManager
       private final LeafCollector[] leafCollectors;
       private final boolean skipNonCompetitiveScores;
 
-      private LeafCollectors(final LeafReaderContext context, boolean skipNonCompetitiveScores) throws IOException {
+      private LeafCollectors(final LeafReaderContext context, boolean skipNonCompetitiveScores)
+          throws IOException {
         this.skipNonCompetitiveScores = skipNonCompetitiveScores;
         leafCollectors = new LeafCollector[collectors.length];
         for (int i = 0; i < collectors.length; i++)
@@ -114,14 +121,14 @@ public class SolrMultiCollectorManager
             if (leafCollector != null) leafCollector.setScorer(scorer);
         } else {
           FilterScorable fScorer =
-                  new FilterScorable(scorer) {
-                    @Override
-                    public void setMinCompetitiveScore(float minScore) throws IOException {
-                      // Ignore calls to setMinCompetitiveScore so that if we wrap two
-                      // collectors and one of them wants to skip low-scoring hits, then
-                      // the other collector still sees all hits.
-                    }
-                  };
+              new FilterScorable(scorer) {
+                @Override
+                public void setMinCompetitiveScore(float minScore) throws IOException {
+                  // Ignore calls to setMinCompetitiveScore so that if we wrap two
+                  // collectors and one of them wants to skip low-scoring hits, then
+                  // the other collector still sees all hits.
+                }
+              };
           for (LeafCollector leafCollector : leafCollectors) {
             if (leafCollector != null) {
               leafCollector.setScorer(fScorer);
diff --git a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java b/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java
index 8384b25b9a2..5285da44b9e 100644
--- a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java
+++ b/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java
@@ -24,418 +24,442 @@ import java.util.concurrent.atomic.AtomicLongArray;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * This is a lock-free, thread-safe version of a {@link java.util.BitSet}.<p>
+ * This is a lock-free, thread-safe version of a {@link java.util.BitSet}.
  *
- * Instead of a long array to hold the bits, this implementation uses an AtomicLongArray, then
+ * <p>Instead of a long array to hold the bits, this implementation uses an AtomicLongArray, then
  * does the appropriate compare-and-swap operations when setting the bits.
- *
- * @author dkoszewnik
- *
  */
 public class ThreadSafeBitSet {
 
-    public static final int DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS = 14;
-
-    private final int numLongsPerSegment;
-    private final int log2SegmentSize;
-    private final int segmentMask;
-    private final AtomicReference<ThreadSafeBitSetSegments> segments;
-
-    public ThreadSafeBitSet() {
-        this(DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS); /// 16384 bits, 2048 bytes, 256 longs per segment
+  public static final int DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS = 14;
+
+  private final int numLongsPerSegment;
+  private final int log2SegmentSize;
+  private final int segmentMask;
+  private final AtomicReference<ThreadSafeBitSetSegments> segments;
+
+  public ThreadSafeBitSet() {
+    this(DEFAULT_LOG2_SEGMENT_SIZE_IN_BITS); // / 16384 bits, 2048 bytes, 256 longs per segment
+  }
+
+  public ThreadSafeBitSet(int log2SegmentSizeInBits) {
+    this(log2SegmentSizeInBits, 0);
+  }
+
+  public ThreadSafeBitSet(int log2SegmentSizeInBits, int numBitsToPreallocate) {
+    if (log2SegmentSizeInBits < 6)
+      throw new IllegalArgumentException("Cannot specify fewer than 64 bits in each segment!");
+
+    this.log2SegmentSize = log2SegmentSizeInBits;
+    this.numLongsPerSegment = (1 << (log2SegmentSizeInBits - 6));
+    this.segmentMask = numLongsPerSegment - 1;
+
+    long numBitsPerSegment = ((long) numLongsPerSegment) * 64;
+    int numSegmentsToPreallocate =
+        numBitsToPreallocate == 0
+            ? 1
+            : (int) (((numBitsToPreallocate - 1) / numBitsPerSegment) + 1);
+
+    segments = new AtomicReference<ThreadSafeBitSetSegments>();
+    segments.set(new ThreadSafeBitSetSegments(numSegmentsToPreallocate, numLongsPerSegment));
+  }
+
+  public void set(int position) {
+    int segmentPosition =
+        position >>> log2SegmentSize; // / which segment -- div by num bits per segment
+    int longPosition =
+        (position >>> 6)
+            & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
+    int bitPosition =
+        position & 0x3F; // / which bit in the long -- remainder of div by num bits in long (64)
+
+    AtomicLongArray segment = getSegment(segmentPosition);
+
+    long mask = 1L << bitPosition;
+
+    // Thread safety: we need to loop until we win the race to set the long value.
+    while (true) {
+      // determine what the new long value will be after we set the appropriate bit.
+      long currentLongValue = segment.get(longPosition);
+      long newLongValue = currentLongValue | mask;
+
+      // if no other thread has modified the value since we read it, we won the race and we are
+      // done.
+      if (segment.compareAndSet(longPosition, currentLongValue, newLongValue)) break;
     }
-
-    public ThreadSafeBitSet(int log2SegmentSizeInBits) {
-        this(log2SegmentSizeInBits, 0);
+  }
+
+  public void clear(int position) {
+    int segmentPosition =
+        position >>> log2SegmentSize; // / which segment -- div by num bits per segment
+    int longPosition =
+        (position >>> 6)
+            & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
+    int bitPosition =
+        position & 0x3F; // / which bit in the long -- remainder of div by num bits in long (64)
+
+    AtomicLongArray segment = getSegment(segmentPosition);
+
+    long mask = ~(1L << bitPosition);
+
+    // Thread safety: we need to loop until we win the race to set the long value.
+    while (true) {
+      // determine what the new long value will be after we set the appropriate bit.
+      long currentLongValue = segment.get(longPosition);
+      long newLongValue = currentLongValue & mask;
+
+      // if no other thread has modified the value since we read it, we won the race and we are
+      // done.
+      if (segment.compareAndSet(longPosition, currentLongValue, newLongValue)) break;
     }
-
-    public ThreadSafeBitSet(int log2SegmentSizeInBits, int numBitsToPreallocate) {
-        if(log2SegmentSizeInBits < 6)
-            throw new IllegalArgumentException("Cannot specify fewer than 64 bits in each segment!");
-
-        this.log2SegmentSize = log2SegmentSizeInBits;
-        this.numLongsPerSegment = (1 << (log2SegmentSizeInBits - 6));
-        this.segmentMask = numLongsPerSegment - 1;
-        
-        long numBitsPerSegment = numLongsPerSegment * 64;
-        int numSegmentsToPreallocate = numBitsToPreallocate == 0 ? 1 : (int)(((numBitsToPreallocate - 1) / numBitsPerSegment) + 1);
-
-        segments = new AtomicReference<ThreadSafeBitSetSegments>();
-        segments.set(new ThreadSafeBitSetSegments(numSegmentsToPreallocate, numLongsPerSegment));
-    }
-
-    public void set(int position) {
-        int segmentPosition = position >>> log2SegmentSize; /// which segment -- div by num bits per segment
-        int longPosition = (position >>> 6) & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
-        int bitPosition = position & 0x3F; /// which bit in the long -- remainder of div by num bits in long (64)
-
-        AtomicLongArray segment = getSegment(segmentPosition);
-
-        long mask = 1L << bitPosition;
-
-        // Thread safety: we need to loop until we win the race to set the long value.
-        while(true) {
-            // determine what the new long value will be after we set the appropriate bit.
-            long currentLongValue = segment.get(longPosition);
-            long newLongValue = currentLongValue | mask;
-
-            // if no other thread has modified the value since we read it, we won the race and we are done.
-            if(segment.compareAndSet(longPosition, currentLongValue, newLongValue))
-                break;
-        }
+  }
+
+  public boolean get(int position) {
+    int segmentPosition =
+        position >>> log2SegmentSize; // / which segment -- div by num bits per segment
+    int longPosition =
+        (position >>> 6)
+            & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
+    int bitPosition =
+        position & 0x3F; // / which bit in the long -- remainder of div by num bits in long (64)
+
+    AtomicLongArray segment = getSegment(segmentPosition);
+
+    long mask = 1L << bitPosition;
+
+    return ((segment.get(longPosition) & mask) != 0);
+  }
+
+  public long maxSetBit() {
+    ThreadSafeBitSetSegments segments = this.segments.get();
+
+    int segmentIdx = segments.numSegments() - 1;
+
+    for (; segmentIdx >= 0; segmentIdx--) {
+      AtomicLongArray segment = segments.getSegment(segmentIdx);
+      for (int longIdx = segment.length() - 1; longIdx >= 0; longIdx--) {
+        long l = segment.get(longIdx);
+        if (l != 0)
+          return (segmentIdx << log2SegmentSize)
+              + (((long) longIdx) * 64)
+              + (63 - Long.numberOfLeadingZeros(l));
+      }
     }
 
-    public void clear(int position) {
-        int segmentPosition = position >>> log2SegmentSize; /// which segment -- div by num bits per segment
-        int longPosition = (position >>> 6) & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
-        int bitPosition = position & 0x3F; /// which bit in the long -- remainder of div by num bits in long (64)
+    return -1;
+  }
 
-        AtomicLongArray segment = getSegment(segmentPosition);
+  public int nextSetBit(int fromIndex) {
+    if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
 
-        long mask = ~(1L << bitPosition);
+    int segmentPosition =
+        fromIndex >>> log2SegmentSize; // / which segment -- div by num bits per segment
 
-        // Thread safety: we need to loop until we win the race to set the long value.
-        while(true) {
-            // determine what the new long value will be after we set the appropriate bit.
-            long currentLongValue = segment.get(longPosition);
-            long newLongValue = currentLongValue & mask;
+    ThreadSafeBitSetSegments segments = this.segments.get();
 
-            // if no other thread has modified the value since we read it, we won the race and we are done.
-            if(segment.compareAndSet(longPosition, currentLongValue, newLongValue))
-                break;
-        }
-    }
+    if (segmentPosition >= segments.numSegments()) return -1;
 
-    public boolean get(int position) {
-        int segmentPosition = position >>> log2SegmentSize; /// which segment -- div by num bits per segment
-        int longPosition = (position >>> 6) & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
-        int bitPosition = position & 0x3F; /// which bit in the long -- remainder of div by num bits in long (64)
+    int longPosition =
+        (fromIndex >>> 6)
+            & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
+    int bitPosition =
+        fromIndex & 0x3F; // / which bit in the long -- remainder of div by num bits in long (64)
+    AtomicLongArray segment = segments.getSegment(segmentPosition);
 
-        AtomicLongArray segment = getSegment(segmentPosition);
+    long word = segment.get(longPosition) & (0xffffffffffffffffL << bitPosition);
 
-        long mask = 1L << bitPosition;
+    while (true) {
+      if (word != 0)
+        return (segmentPosition << (log2SegmentSize))
+            + (longPosition << 6)
+            + Long.numberOfTrailingZeros(word);
+      if (++longPosition > segmentMask) {
+        segmentPosition++;
+        if (segmentPosition >= segments.numSegments()) return -1;
+        segment = segments.getSegment(segmentPosition);
+        longPosition = 0;
+      }
 
-        return ((segment.get(longPosition) & mask) != 0);
+      word = segment.get(longPosition);
     }
+  }
 
-    public long maxSetBit() {
-        ThreadSafeBitSetSegments segments = this.segments.get();
+  /**
+   * @return the number of bits which are set in this bit set.
+   */
+  public int cardinality() {
+    ThreadSafeBitSetSegments segments = this.segments.get();
 
-        int segmentIdx = segments.numSegments() - 1;
-
-        for(;segmentIdx >= 0; segmentIdx--) {
-            AtomicLongArray segment = segments.getSegment(segmentIdx);
-            for(int longIdx=segment.length() - 1; longIdx >= 0; longIdx--) {
-                long l = segment.get(longIdx);
-                if(l != 0)
-                    return (segmentIdx << log2SegmentSize) + (longIdx * 64) + (63 - Long.numberOfLeadingZeros(l));
-            }
-        }
+    int numSetBits = 0;
 
-        return -1;
+    for (int i = 0; i < segments.numSegments(); i++) {
+      AtomicLongArray segment = segments.getSegment(i);
+      for (int j = 0; j < segment.length(); j++) {
+        numSetBits += Long.bitCount(segment.get(j));
+      }
     }
 
-    public int nextSetBit(int fromIndex) {
-        if (fromIndex < 0)
-            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
-
-        int segmentPosition = fromIndex >>> log2SegmentSize; /// which segment -- div by num bits per segment
-
-        ThreadSafeBitSetSegments segments = this.segments.get();
-
-        if(segmentPosition >= segments.numSegments())
-            return -1;
-
-        int longPosition = (fromIndex >>> 6) & segmentMask; /// which long in the segment -- remainder of div by num bits per segment
-        int bitPosition = fromIndex & 0x3F; /// which bit in the long -- remainder of div by num bits in long (64)
-        AtomicLongArray segment = segments.getSegment(segmentPosition);
-
-        long word = segment.get(longPosition) & (0xffffffffffffffffL << bitPosition);
-
-        while (true) {
-            if (word != 0)
-                return (segmentPosition << (log2SegmentSize)) + (longPosition << 6) + Long.numberOfTrailingZeros(word);
-            if (++longPosition > segmentMask) {
-                segmentPosition++;
-                if(segmentPosition >= segments.numSegments())
-                    return -1;
-                segment = segments.getSegment(segmentPosition);
-                longPosition = 0;
-            }
-
-            word = segment.get(longPosition);
-        }
-    }
-
-
-    /**
-     * @return the number of bits which are set in this bit set.
-     */
-    public int cardinality() {
-        ThreadSafeBitSetSegments segments = this.segments.get();
+    return numSetBits;
+  }
 
-        int numSetBits = 0;
+  /**
+   * @return the number of bits which are current specified by this bit set. This is the maximum
+   *     value to which you might need to iterate, if you were to iterate over all bits in this set.
+   */
+  public int currentCapacity() {
+    return segments.get().numSegments() * (1 << log2SegmentSize);
+  }
 
-        for(int i=0;i<segments.numSegments();i++) {
-            AtomicLongArray segment = segments.getSegment(i);
-            for(int j=0;j<segment.length();j++) {
-                numSetBits += Long.bitCount(segment.get(j));
-            }
-        }
+  /** Clear all bits to 0. */
+  public void clearAll() {
+    ThreadSafeBitSetSegments segments = this.segments.get();
 
-        return numSetBits;
-    }
+    for (int i = 0; i < segments.numSegments(); i++) {
+      AtomicLongArray segment = segments.getSegment(i);
 
-    /**
-     * @return the number of bits which are current specified by this bit set.  This is the maximum value
-     * to which you might need to iterate, if you were to iterate over all bits in this set.
-     */
-    public int currentCapacity() {
-        return segments.get().numSegments() * (1 << log2SegmentSize);
+      for (int j = 0; j < segment.length(); j++) {
+        segment.set(j, 0L);
+      }
     }
-
-    /**
-     * Clear all bits to 0.
-     */
-    public void clearAll() {
-        ThreadSafeBitSetSegments segments = this.segments.get();
-
-        for(int i=0;i<segments.numSegments();i++) {
-            AtomicLongArray segment = segments.getSegment(i);
-
-            for(int j=0;j<segment.length();j++) {
-                segment.set(j, 0L);
-            }
-        }
+  }
+
+  /**
+   * Return a new bit set which contains all bits which are contained in this bit set, and which are
+   * NOT contained in the <code>other</code> bit set.
+   *
+   * <p>In other words, return a new bit set, which is a bitwise and with the bitwise not of the
+   * other bit set.
+   *
+   * @param other the other bit set
+   * @return the resulting bit set
+   */
+  public ThreadSafeBitSet andNot(ThreadSafeBitSet other) {
+    if (other.log2SegmentSize != log2SegmentSize)
+      throw new IllegalArgumentException("Segment sizes must be the same");
+
+    ThreadSafeBitSetSegments thisSegments = this.segments.get();
+    ThreadSafeBitSetSegments otherSegments = other.segments.get();
+    ThreadSafeBitSetSegments newSegments =
+        new ThreadSafeBitSetSegments(thisSegments.numSegments(), numLongsPerSegment);
+
+    for (int i = 0; i < thisSegments.numSegments(); i++) {
+      AtomicLongArray thisArray = thisSegments.getSegment(i);
+      AtomicLongArray otherArray =
+          (i < otherSegments.numSegments()) ? otherSegments.getSegment(i) : null;
+      AtomicLongArray newArray = newSegments.getSegment(i);
+
+      for (int j = 0; j < thisArray.length(); j++) {
+        long thisLong = thisArray.get(j);
+        long otherLong = (otherArray == null) ? 0 : otherArray.get(j);
+
+        newArray.set(j, thisLong & ~otherLong);
+      }
     }
 
-    /**
-     * Return a new bit set which contains all bits which are contained in this bit set, and which are NOT contained in the <code>other</code> bit set.<p>
-     *
-     * In other words, return a new bit set, which is a bitwise and with the bitwise not of the other bit set.
-     *
-     * @param other the other bit set
-     * @return the resulting bit set
-     */
-    public ThreadSafeBitSet andNot(ThreadSafeBitSet other) {
-        if(other.log2SegmentSize != log2SegmentSize)
-            throw new IllegalArgumentException("Segment sizes must be the same");
-
-        ThreadSafeBitSetSegments thisSegments = this.segments.get();
-        ThreadSafeBitSetSegments otherSegments = other.segments.get();
-        ThreadSafeBitSetSegments newSegments = new ThreadSafeBitSetSegments(thisSegments.numSegments(), numLongsPerSegment);
-
-        for(int i=0;i<thisSegments.numSegments();i++) {
-            AtomicLongArray thisArray = thisSegments.getSegment(i);
-            AtomicLongArray otherArray = (i < otherSegments.numSegments()) ? otherSegments.getSegment(i) : null;
-            AtomicLongArray newArray = newSegments.getSegment(i);
-
-            for(int j=0;j<thisArray.length();j++) {
-                long thisLong = thisArray.get(j);
-                long otherLong = (otherArray == null) ? 0 : otherArray.get(j);
-
-                newArray.set(j, thisLong & ~otherLong);
-            }
-        }
-
-        ThreadSafeBitSet andNot = new ThreadSafeBitSet(log2SegmentSize);
-        andNot.segments.set(newSegments);
-        return andNot;
+    ThreadSafeBitSet andNot = new ThreadSafeBitSet(log2SegmentSize);
+    andNot.segments.set(newSegments);
+    return andNot;
+  }
+
+  /**
+   * Return a new bit set which contains all bits which are contained in *any* of the specified bit
+   * sets.
+   *
+   * @param bitSets the other bit sets
+   * @return the resulting bit set
+   */
+  public static ThreadSafeBitSet orAll(ThreadSafeBitSet... bitSets) {
+    if (bitSets.length == 0) return new ThreadSafeBitSet();
+
+    int log2SegmentSize = bitSets[0].log2SegmentSize;
+    int numLongsPerSegment = bitSets[0].numLongsPerSegment;
+
+    ThreadSafeBitSetSegments segments[] = new ThreadSafeBitSetSegments[bitSets.length];
+    int maxNumSegments = 0;
+
+    for (int i = 0; i < bitSets.length; i++) {
+      if (bitSets[i].log2SegmentSize != log2SegmentSize)
+        throw new IllegalArgumentException("Segment sizes must be the same");
+
+      segments[i] = bitSets[i].segments.get();
+      if (segments[i].numSegments() > maxNumSegments) maxNumSegments = segments[i].numSegments();
     }
 
-    /**
-     * Return a new bit set which contains all bits which are contained in *any* of the specified bit sets.
-     *
-     * @param bitSets the other bit sets
-     * @return the resulting bit set
-     */
-    public static ThreadSafeBitSet orAll(ThreadSafeBitSet... bitSets) {
-        if(bitSets.length == 0)
-            return new ThreadSafeBitSet();
-
-        int log2SegmentSize = bitSets[0].log2SegmentSize;
-        int numLongsPerSegment = bitSets[0].numLongsPerSegment;
-
-        ThreadSafeBitSetSegments segments[] = new ThreadSafeBitSetSegments[bitSets.length];
-        int maxNumSegments = 0;
-
-        for(int i=0;i<bitSets.length;i++) {
-            if(bitSets[i].log2SegmentSize != log2SegmentSize)
-                throw new IllegalArgumentException("Segment sizes must be the same");
-
-            segments[i] = bitSets[i].segments.get();
-            if(segments[i].numSegments() > maxNumSegments)
-                maxNumSegments = segments[i].numSegments();
-        }
-
-        ThreadSafeBitSetSegments newSegments = new ThreadSafeBitSetSegments(maxNumSegments, numLongsPerSegment);
+    ThreadSafeBitSetSegments newSegments =
+        new ThreadSafeBitSetSegments(maxNumSegments, numLongsPerSegment);
 
-        AtomicLongArray segment[] = new AtomicLongArray[segments.length];
+    AtomicLongArray segment[] = new AtomicLongArray[segments.length];
 
-        for(int i=0;i<maxNumSegments;i++) {
-            for(int j=0;j<segments.length;j++) {
-                segment[j] = i < segments[j].numSegments() ? segments[j].getSegment(i) : null;
-            }
+    for (int i = 0; i < maxNumSegments; i++) {
+      for (int j = 0; j < segments.length; j++) {
+        segment[j] = i < segments[j].numSegments() ? segments[j].getSegment(i) : null;
+      }
 
-            AtomicLongArray newSegment = newSegments.getSegment(i);
+      AtomicLongArray newSegment = newSegments.getSegment(i);
 
-            for(int j=0;j<numLongsPerSegment;j++) {
-                long value = 0;
-                for(int k=0;k<segments.length;k++) {
-                    if(segment[k] != null)
-                        value |= segment[k].get(j);
-                }
-                newSegment.set(j, value);
-            }
+      for (int j = 0; j < numLongsPerSegment; j++) {
+        long value = 0;
+        for (int k = 0; k < segments.length; k++) {
+          if (segment[k] != null) value |= segment[k].get(j);
         }
-
-        ThreadSafeBitSet or = new ThreadSafeBitSet(log2SegmentSize);
-        or.segments.set(newSegments);
-        return or;
+        newSegment.set(j, value);
+      }
     }
 
-    /**
-     * Get the segment at <code>segmentIndex</code>.  If this segment does not yet exist, create it.
-     *
-     * @param segmentIndex the segment index
-     * @return the segment
-     */
-    private AtomicLongArray getSegment(int segmentIndex) {
-        ThreadSafeBitSetSegments visibleSegments = segments.get();
-
-        while(visibleSegments.numSegments() <= segmentIndex) {
-            /// Thread safety:  newVisibleSegments contains all of the segments from the currently visible segments, plus extra.
-            /// all of the segments in the currently visible segments are canonical and will not change.
-            ThreadSafeBitSetSegments newVisibleSegments = new ThreadSafeBitSetSegments(visibleSegments, segmentIndex + 1, numLongsPerSegment);
-
-            /// because we are using a compareAndSet, if this thread "wins the race" and successfully sets this variable, then the segments
-            /// which are newly defined in newVisibleSegments become canonical.
-            if(segments.compareAndSet(visibleSegments, newVisibleSegments)) {
-                visibleSegments = newVisibleSegments;
-            } else {
-                /// If we "lose the race" and are growing the ThreadSafeBitSet segments larger,
-                /// then we will gather the new canonical sets from the update which we missed on the next iteration of this loop.
-                /// Newly defined segments in newVisibleSegments will be discarded, they do not get to become canonical.
-                visibleSegments = segments.get();
-            }
-        }
-
-        return visibleSegments.getSegment(segmentIndex);
+    ThreadSafeBitSet or = new ThreadSafeBitSet(log2SegmentSize);
+    or.segments.set(newSegments);
+    return or;
+  }
+
+  /**
+   * Get the segment at <code>segmentIndex</code>. If this segment does not yet exist, create it.
+   *
+   * @param segmentIndex the segment index
+   * @return the segment
+   */
+  private AtomicLongArray getSegment(int segmentIndex) {
+    ThreadSafeBitSetSegments visibleSegments = segments.get();
+
+    while (visibleSegments.numSegments() <= segmentIndex) {
+      /// Thread safety:  newVisibleSegments contains all of the segments from the currently visible
+      // segments, plus extra.
+      /// all of the segments in the currently visible segments are canonical and will not change.
+      ThreadSafeBitSetSegments newVisibleSegments =
+          new ThreadSafeBitSetSegments(visibleSegments, segmentIndex + 1, numLongsPerSegment);
+
+      /// because we are using a compareAndSet, if this thread "wins the race" and successfully sets
+      // this variable, then the segments
+      /// which are newly defined in newVisibleSegments become canonical.
+      if (segments.compareAndSet(visibleSegments, newVisibleSegments)) {
+        visibleSegments = newVisibleSegments;
+      } else {
+        /// If we "lose the race" and are growing the ThreadSafeBitSet segments larger,
+        /// then we will gather the new canonical sets from the update which we missed on the next
+        // iteration of this loop.
+        /// Newly defined segments in newVisibleSegments will be discarded, they do not get to
+        // become canonical.
+        visibleSegments = segments.get();
+      }
     }
 
-    private static class ThreadSafeBitSetSegments {
-
-        private final AtomicLongArray segments[];
-
-        private ThreadSafeBitSetSegments(int numSegments, int segmentLength) {
-            AtomicLongArray segments[] = new AtomicLongArray[numSegments];
+    return visibleSegments.getSegment(segmentIndex);
+  }
 
-            for(int i=0;i<numSegments;i++) {
-                segments[i] = new AtomicLongArray(segmentLength);
-            }
+  private static class ThreadSafeBitSetSegments {
 
-            /// Thread safety: Because this.segments is final, the preceding operations in this constructor are guaranteed to be visible to any
-            /// other thread which accesses this.segments.
-            this.segments = segments;
-        }
+    private final AtomicLongArray segments[];
 
-        private ThreadSafeBitSetSegments(ThreadSafeBitSetSegments copyFrom, int numSegments, int segmentLength) {
-            AtomicLongArray segments[] = new AtomicLongArray[numSegments];
+    private ThreadSafeBitSetSegments(int numSegments, int segmentLength) {
+      AtomicLongArray segments[] = new AtomicLongArray[numSegments];
 
-            for(int i=0;i<numSegments;i++) {
-                segments[i] = i < copyFrom.numSegments() ? copyFrom.getSegment(i) : new AtomicLongArray(segmentLength);
-            }
+      for (int i = 0; i < numSegments; i++) {
+        segments[i] = new AtomicLongArray(segmentLength);
+      }
 
-            /// see above re: thread-safety of this assignment
-            this.segments = segments;
-        }
+      /// Thread safety: Because this.segments is final, the preceding operations in this
+      // constructor are guaranteed to be visible to any
+      /// other thread which accesses this.segments.
+      this.segments = segments;
+    }
 
-        public int numSegments() {
-            return segments.length;
-        }
+    private ThreadSafeBitSetSegments(
+        ThreadSafeBitSetSegments copyFrom, int numSegments, int segmentLength) {
+      AtomicLongArray segments[] = new AtomicLongArray[numSegments];
 
-        public AtomicLongArray getSegment(int index) {
-            return segments[index];
-        }
+      for (int i = 0; i < numSegments; i++) {
+        segments[i] =
+            i < copyFrom.numSegments()
+                ? copyFrom.getSegment(i)
+                : new AtomicLongArray(segmentLength);
+      }
 
+      /// see above re: thread-safety of this assignment
+      this.segments = segments;
     }
 
-    public void serializeBitsTo(DataOutputStream os) throws IOException {
-        ThreadSafeBitSetSegments segments = this.segments.get();
-
-        os.writeInt(segments.numSegments() * numLongsPerSegment);
-
-        for(int i=0;i<segments.numSegments();i++) {
-            AtomicLongArray arr = segments.getSegment(i);
+    public int numSegments() {
+      return segments.length;
+    }
 
-            for(int j=0;j<arr.length();j++) {
-                os.writeLong(arr.get(j));
-            }
-        }
+    public AtomicLongArray getSegment(int index) {
+      return segments[index];
     }
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if(!(obj instanceof ThreadSafeBitSet))
-            return false;
+  public void serializeBitsTo(DataOutputStream os) throws IOException {
+    ThreadSafeBitSetSegments segments = this.segments.get();
 
-        ThreadSafeBitSet other = (ThreadSafeBitSet)obj;
+    os.writeInt(segments.numSegments() * numLongsPerSegment);
 
-        if(other.log2SegmentSize != log2SegmentSize)
-            throw new IllegalArgumentException("Segment sizes must be the same");
+    for (int i = 0; i < segments.numSegments(); i++) {
+      AtomicLongArray arr = segments.getSegment(i);
 
-        ThreadSafeBitSetSegments thisSegments = this.segments.get();
-        ThreadSafeBitSetSegments otherSegments = other.segments.get();
+      for (int j = 0; j < arr.length(); j++) {
+        os.writeLong(arr.get(j));
+      }
+    }
+  }
 
-        for(int i=0;i<thisSegments.numSegments();i++) {
-            AtomicLongArray thisArray = thisSegments.getSegment(i);
-            AtomicLongArray otherArray = (i < otherSegments.numSegments()) ? otherSegments.getSegment(i) : null;
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof ThreadSafeBitSet)) return false;
 
-            for(int j=0;j<thisArray.length();j++) {
-                long thisLong = thisArray.get(j);
-                long otherLong = (otherArray == null) ? 0 : otherArray.get(j);
+    ThreadSafeBitSet other = (ThreadSafeBitSet) obj;
 
-                if(thisLong != otherLong)
-                    return false;
-            }
-        }
+    if (other.log2SegmentSize != log2SegmentSize)
+      throw new IllegalArgumentException("Segment sizes must be the same");
 
-        for(int i=thisSegments.numSegments();i<otherSegments.numSegments();i++) {
-            AtomicLongArray otherArray = otherSegments.getSegment(i);
+    ThreadSafeBitSetSegments thisSegments = this.segments.get();
+    ThreadSafeBitSetSegments otherSegments = other.segments.get();
 
-            for(int j=0;j<otherArray.length();j++) {
-                long l = otherArray.get(j);
+    for (int i = 0; i < thisSegments.numSegments(); i++) {
+      AtomicLongArray thisArray = thisSegments.getSegment(i);
+      AtomicLongArray otherArray =
+          (i < otherSegments.numSegments()) ? otherSegments.getSegment(i) : null;
 
-                if(l != 0)
-                    return false;
-            }
-        }
+      for (int j = 0; j < thisArray.length(); j++) {
+        long thisLong = thisArray.get(j);
+        long otherLong = (otherArray == null) ? 0 : otherArray.get(j);
 
-        return true;
+        if (thisLong != otherLong) return false;
+      }
     }
 
-    @Override
-    public int hashCode() {
-        int result = log2SegmentSize;
-        result = 31 * result + Arrays.hashCode(segments.get().segments);
-        return result;
-    }
+    for (int i = thisSegments.numSegments(); i < otherSegments.numSegments(); i++) {
+      AtomicLongArray otherArray = otherSegments.getSegment(i);
 
-    /**
-     * @return a new BitSet with same bits set
-     */
-    public BitSet toBitSet() {
-        BitSet resultSet = new BitSet();
-        int ordinal = this.nextSetBit(0);
-        while(ordinal!=-1) {
-            resultSet.set(ordinal);
-            ordinal = this.nextSetBit(ordinal + 1);
-        }
-        return resultSet;
+      for (int j = 0; j < otherArray.length(); j++) {
+        long l = otherArray.get(j);
+
+        if (l != 0) return false;
+      }
     }
 
-    @Override
-    public String toString() {
-        return toBitSet().toString();
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = log2SegmentSize;
+    result = 31 * result + Arrays.hashCode(segments.get().segments);
+    return result;
+  }
+
+  /**
+   * @return a new BitSet with same bits set
+   */
+  public BitSet toBitSet() {
+    BitSet resultSet = new BitSet();
+    int ordinal = this.nextSetBit(0);
+    while (ordinal != -1) {
+      resultSet.set(ordinal);
+      ordinal = this.nextSetBit(ordinal + 1);
     }
-}
\ No newline at end of file
+    return resultSet;
+  }
+
+  @Override
+  public String toString() {
+    return toBitSet().toString();
+  }
+}
diff --git a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSetCollector.java b/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSetCollector.java
index 626d01ce168..426d3b64788 100644
--- a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSetCollector.java
+++ b/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSetCollector.java
@@ -16,6 +16,8 @@
  */
 package org.apache.solr.search;
 
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Scorable;
 import org.apache.lucene.search.ScoreMode;
@@ -24,13 +26,7 @@ import org.apache.lucene.util.FixedBitSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-
-/**
- *
- */
-
+/** */
 public class ThreadSafeBitSetCollector extends SimpleCollector {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   final ThreadSafeBitSet bits;
@@ -38,21 +34,19 @@ public class ThreadSafeBitSetCollector extends SimpleCollector {
 
   int base;
 
-
-
   public ThreadSafeBitSetCollector(ThreadSafeBitSet bits, int maxDoc) {
     this.bits = bits;
     this.maxDoc = maxDoc;
   }
 
-
   @Override
   public void collect(int doc) throws IOException {
 
     doc += base;
-    log.error("collect doc {} {}", (doc + base), this);
-      bits.set(doc);
-
+    if (log.isErrorEnabled()) {
+      log.error("collect doc: {}, base: {}", doc, base, this);
+    }
+    bits.set(doc);
   }
 
   /** The number of documents that have been collected */
@@ -67,7 +61,7 @@ public class ThreadSafeBitSetCollector extends SimpleCollector {
     int cnt = 0;
     int i = -1;
     while (true) {
-      i = bits.nextSetBit(i+1);
+      i = bits.nextSetBit(i + 1);
       if (i == -1) {
         break;
       }
@@ -76,12 +70,10 @@ public class ThreadSafeBitSetCollector extends SimpleCollector {
     }
 
     return new BitDocSet(fixedBitSet, cnt);
-
   }
 
   @Override
-  public void setScorer(Scorable scorer) throws IOException {
-  }
+  public void setScorer(Scorable scorer) throws IOException {}
 
   @Override
   public ScoreMode scoreMode() {
@@ -91,7 +83,8 @@ public class ThreadSafeBitSetCollector extends SimpleCollector {
   @Override
   protected void doSetNextReader(LeafReaderContext context) throws IOException {
     this.base = context.docBase;
-    log.error("next reader base=" + base);
+    if (log.isErrorEnabled()) {
+      log.error("next reader base={}", base);
+    }
   }
-
 }
diff --git a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
index fb3a1137734..7b99a95fe21 100644
--- a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
+++ b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java
@@ -1786,7 +1786,7 @@ public class TestDistributedSearch extends BaseDistributedSearchTestCase {
         CommonParams.ROWS,
         "200",
         CommonParams.SORT,
-        "score desc, id asc");
+        "id asc");
     assertIsExactHitCount(
         "q", "{!cache=false}id:1", CommonParams.MIN_EXACT_COUNT, "1", CommonParams.ROWS, "1");
     assertApproximatedHitCount(
diff --git a/solr/core/src/test/org/apache/solr/search/TestFiltering.java b/solr/core/src/test/org/apache/solr/search/TestFiltering.java
index e59e007cafb..e9194e170f9 100644
--- a/solr/core/src/test/org/apache/solr/search/TestFiltering.java
+++ b/solr/core/src/test/org/apache/solr/search/TestFiltering.java
@@ -93,19 +93,14 @@ public class TestFiltering extends SolrTestCaseJ4 {
         QueryResult res = new QueryResult();
         searcher.search(res, cmd);
         set = res.getDocSet();
-        assertSame(set, live);
-         System.out.println("Live: "+bitsString(live.getFixedBitSet()));
-         System.out.println("Set: "+bitsString(set.getFixedBitSet()));
-     //   FixedBitSet xor = live.getFixedBitSet().clone();
-     //   xor.xor(set.getFixedBitSet());
-        // System.out.println("xor: "+bitsString(xor));
+        assertEffectivelySame(set.getFixedBitSet(), live.getFixedBitSet());
 
         cmd.setQuery(QParser.getParser(qstr + " OR id:0", null, req).getQuery());
         cmd.setFilterList(QParser.getParser(qstr + " OR id:1", null, req).getQuery());
         res = new QueryResult();
         searcher.search(res, cmd);
         set = res.getDocSet();
-        assertSame(set, live);
+        assertEffectivelySame(set.getFixedBitSet(), live.getFixedBitSet());
       }
 
     } finally {
@@ -113,14 +108,20 @@ public class TestFiltering extends SolrTestCaseJ4 {
     }
   }
 
+  /** If the a XOR b == 0, then both a & b are effectively the same bitset */
+  private void assertEffectivelySame(FixedBitSet a, FixedBitSet b) {
+    FixedBitSet xor = a.clone();
+    xor.xor(b);
+    assertEquals(new FixedBitSet(xor.length()), xor);
+  }
+
   private String bitsString(Bits bits) {
     StringBuilder s = new StringBuilder();
-    for (int i=0; i<bits.length(); i++)
-      s.append(bits.get(i) ? 1 : 0);
+    for (int i = 0; i < bits.length(); i++) s.append(bits.get(i) ? 1 : 0);
     return s.toString();
   }
 
-    public void testCaching() throws Exception {
+  public void testCaching() throws Exception {
     clearIndex();
     assertU(adoc("id", "4", "val_i", "1"));
     assertU(adoc("id", "1", "val_i", "2"));