You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by cp...@apache.org on 2024/03/04 14:14:26 UTC

(solr) 01/03: Revert "Revert "tentative: replace ThreadSafeBitSet[Collector] with FixedBitSet[Collector]""

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

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

commit 00a06bcff588222b527b6b0371749ef4d36ca150
Author: Christine Poerschke <cp...@apache.org>
AuthorDate: Mon Mar 4 13:18:16 2024 +0000

    Revert "Revert "tentative: replace ThreadSafeBitSet[Collector] with FixedBitSet[Collector]""
    
    This reverts commit fd0d5abfac14c94b0fcfa6acebe04aa15c372503.
---
 .../org/apache/solr/search/SolrIndexSearcher.java  |  73 ++--
 .../org/apache/solr/search/ThreadSafeBitSet.java   | 465 ---------------------
 .../solr/search/ThreadSafeBitSetCollector.java     |  90 ----
 3 files changed, 37 insertions(+), 591 deletions(-)

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 c637a1dbeec..bba34a9eca3 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -2065,40 +2065,24 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       int maxDoc = rawReader.maxDoc();
       log.error("raw read max={}", rawReader.maxDoc());
 
-      LeafSlice[] leaves = getSlices();
-      int[] docBase = new int[1];
-
-      //   DocSetCollector collector = new DocSetCollector(maxDoc);
-
-      ThreadSafeBitSet bits = new ThreadSafeBitSet(14, 2);
-
       collectors.add(
           new CollectorManager<>() {
             @Override
             public Collector newCollector() throws IOException {
-              int numDocs = 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());
-
               // TODO: add to firstCollectors here? or if not have comment w.r.t. why not adding
-              return new ThreadSafeBitSetCollector(bits, maxDoc);
+              return new FixedBitSetCollector(maxDoc);
             }
 
             @Override
             @SuppressWarnings({"rawtypes"})
             public Object reduce(Collection collectors) throws IOException {
-
-              return new DocSetResult(
-                  ((ThreadSafeBitSetCollector) collectors.iterator().next()).getDocSet());
+              final FixedBitSet reduced = new FixedBitSet(maxDoc);
+              for (Object collector : collectors) {
+                if (collector instanceof FixedBitSetCollector) {
+                  reduced.or(((FixedBitSetCollector) collector).bitSet);
+                }
+              }
+              return reduced;
             }
           });
     }
@@ -2126,6 +2110,31 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
     return new SearchResult(scoreMode, ret);
   }
 
+  static class FixedBitSetCollector extends SimpleCollector {
+    final FixedBitSet bitSet;
+
+    private int docBase;
+
+    FixedBitSetCollector(int maxDoc) {
+      this.bitSet = new FixedBitSet(maxDoc);
+    }
+
+    @Override
+    protected void doSetNextReader(LeafReaderContext context) throws IOException {
+      this.docBase = context.docBase;
+    }
+
+    @Override
+    public void collect(int doc) throws IOException {
+      this.bitSet.set(this.docBase + doc);
+    }
+
+    @Override
+    public ScoreMode scoreMode() {
+      return ScoreMode.COMPLETE_NO_SCORES;
+    }
+  }
+
   static class TopDocsResult {
     final TopDocs topDocs;
     final int totalHits;
@@ -2144,14 +2153,6 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
     }
   }
 
-  static class DocSetResult {
-    final DocSet docSet;
-
-    public DocSetResult(DocSet docSet) {
-      this.docSet = docSet;
-    }
-  }
-
   static class SearchResult {
     final ScoreMode scoreMode;
     private final Object[] result;
@@ -2183,10 +2184,10 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
       }
     }
 
-    public DocSet getDocSet() {
+    public FixedBitSet getFixedBitSet() {
       for (Object res : result) {
-        if (res instanceof DocSetResult) {
-          return ((DocSetResult) res).docSet;
+        if (res instanceof FixedBitSet) {
+          return (FixedBitSet) res;
         }
       }
       return null;
@@ -2299,7 +2300,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
         totalHits = topDocsResult.totalHits;
         topDocs = topDocsResult.topDocs;
         maxScore = searchResult.getMaxScore(totalHits);
-        set = searchResult.getDocSet();
+        set = new BitDocSet(searchResult.getFixedBitSet());
 
         // TODO: Is this correct?
         // hitsRelation = populateScoresIfNeeded(cmd, needScores, topDocs, query,
diff --git a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java b/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java
deleted file mode 100644
index 5285da44b9e..00000000000
--- a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSet.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- *  Copyright 2016-2019 Netflix, Inc.
- *
- *     Licensed under the Apache License, Version 2.0 (the "License");
- *     you may not use this file except in compliance with the License.
- *     You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- *     Unless required by applicable law or agreed to in writing, software
- *     distributed under the License is distributed on an "AS IS" BASIS,
- *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *     See the License for the specific language governing permissions and
- *     limitations under the License.
- *
- */
-package org.apache.solr.search;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.BitSet;
-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>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.
- */
-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 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 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 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));
-      }
-    }
-
-    return -1;
-  }
-
-  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();
-
-    int numSetBits = 0;
-
-    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));
-      }
-    }
-
-    return numSetBits;
-  }
-
-  /**
-   * @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);
-  }
-
-  /** 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);
-      }
-    }
-
-    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();
-    }
-
-    ThreadSafeBitSetSegments newSegments =
-        new ThreadSafeBitSetSegments(maxNumSegments, numLongsPerSegment);
-
-    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;
-      }
-
-      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);
-      }
-    }
-
-    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();
-      }
-    }
-
-    return visibleSegments.getSegment(segmentIndex);
-  }
-
-  private static class ThreadSafeBitSetSegments {
-
-    private final AtomicLongArray segments[];
-
-    private ThreadSafeBitSetSegments(int numSegments, int segmentLength) {
-      AtomicLongArray segments[] = new AtomicLongArray[numSegments];
-
-      for (int i = 0; i < numSegments; i++) {
-        segments[i] = new AtomicLongArray(segmentLength);
-      }
-
-      /// 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 ThreadSafeBitSetSegments(
-        ThreadSafeBitSetSegments copyFrom, 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);
-      }
-
-      /// see above re: thread-safety of this assignment
-      this.segments = segments;
-    }
-
-    public int numSegments() {
-      return segments.length;
-    }
-
-    public AtomicLongArray getSegment(int index) {
-      return segments[index];
-    }
-  }
-
-  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);
-
-      for (int j = 0; j < arr.length(); j++) {
-        os.writeLong(arr.get(j));
-      }
-    }
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (!(obj instanceof ThreadSafeBitSet)) return false;
-
-    ThreadSafeBitSet other = (ThreadSafeBitSet) obj;
-
-    if (other.log2SegmentSize != log2SegmentSize)
-      throw new IllegalArgumentException("Segment sizes must be the same");
-
-    ThreadSafeBitSetSegments thisSegments = this.segments.get();
-    ThreadSafeBitSetSegments otherSegments = other.segments.get();
-
-    for (int i = 0; i < thisSegments.numSegments(); i++) {
-      AtomicLongArray thisArray = thisSegments.getSegment(i);
-      AtomicLongArray otherArray =
-          (i < otherSegments.numSegments()) ? otherSegments.getSegment(i) : null;
-
-      for (int j = 0; j < thisArray.length(); j++) {
-        long thisLong = thisArray.get(j);
-        long otherLong = (otherArray == null) ? 0 : otherArray.get(j);
-
-        if (thisLong != otherLong) return false;
-      }
-    }
-
-    for (int i = thisSegments.numSegments(); i < otherSegments.numSegments(); i++) {
-      AtomicLongArray otherArray = otherSegments.getSegment(i);
-
-      for (int j = 0; j < otherArray.length(); j++) {
-        long l = otherArray.get(j);
-
-        if (l != 0) return false;
-      }
-    }
-
-    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);
-    }
-    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
deleted file mode 100644
index 426d3b64788..00000000000
--- a/solr/core/src/java/org/apache/solr/search/ThreadSafeBitSetCollector.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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;
-import org.apache.lucene.search.SimpleCollector;
-import org.apache.lucene.util.FixedBitSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** */
-public class ThreadSafeBitSetCollector extends SimpleCollector {
-  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-  final ThreadSafeBitSet bits;
-  final int maxDoc;
-
-  int base;
-
-  public ThreadSafeBitSetCollector(ThreadSafeBitSet bits, int maxDoc) {
-    this.bits = bits;
-    this.maxDoc = maxDoc;
-  }
-
-  @Override
-  public void collect(int doc) throws IOException {
-
-    doc += base;
-    if (log.isErrorEnabled()) {
-      log.error("collect doc: {}, base: {}", doc, base, this);
-    }
-    bits.set(doc);
-  }
-
-  /** The number of documents that have been collected */
-  public int size() {
-    return maxDoc;
-  }
-
-  public DocSet getDocSet() {
-    log.error("Max Set Bit {}", bits.maxSetBit());
-
-    FixedBitSet fixedBitSet = new FixedBitSet(maxDoc + 1);
-    int cnt = 0;
-    int i = -1;
-    while (true) {
-      i = bits.nextSetBit(i + 1);
-      if (i == -1) {
-        break;
-      }
-      cnt++;
-      fixedBitSet.set(i);
-    }
-
-    return new BitDocSet(fixedBitSet, cnt);
-  }
-
-  @Override
-  public void setScorer(Scorable scorer) throws IOException {}
-
-  @Override
-  public ScoreMode scoreMode() {
-    return ScoreMode.COMPLETE_NO_SCORES;
-  }
-
-  @Override
-  protected void doSetNextReader(LeafReaderContext context) throws IOException {
-    this.base = context.docBase;
-    if (log.isErrorEnabled()) {
-      log.error("next reader base={}", base);
-    }
-  }
-}