diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index caa8f37246f..ff18177fb0d 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -85,7 +85,11 @@ Changes in backwards compatibility policy non-point shapes. If you want to call makeDistanceValueSource() based on shape centers, you need to do this yourself in another spatial field. (David Smiley) - + +* LUCENE-4615: Replace IntArrayAllocator and FloatArrayAllocator by ArraysPool. + FacetArrays no longer takes those allocators; if you need to reuse the arrays, + you should use ReusingFacetArrays. (Shai Erera, Gilad Barkai) + New Features * LUCENE-4226: New experimental StoredFieldsFormat that compresses chunks of diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/AdaptiveFacetsAccumulator.java b/lucene/facet/src/java/org/apache/lucene/facet/search/AdaptiveFacetsAccumulator.java index faeae37b3be..a7bf378f2d2 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/search/AdaptiveFacetsAccumulator.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/search/AdaptiveFacetsAccumulator.java @@ -2,18 +2,15 @@ package org.apache.lucene.facet.search; import java.io.IOException; import java.util.List; -import java.util.Random; - -import org.apache.lucene.index.IndexReader; import org.apache.lucene.facet.search.params.FacetSearchParams; import org.apache.lucene.facet.search.results.FacetResult; import org.apache.lucene.facet.search.results.FacetResultNode; import org.apache.lucene.facet.search.sampling.RandomSampler; -import org.apache.lucene.facet.search.sampling.RepeatableSampler; import org.apache.lucene.facet.search.sampling.Sampler; import org.apache.lucene.facet.search.sampling.SamplingAccumulator; import org.apache.lucene.facet.taxonomy.TaxonomyReader; +import org.apache.lucene.index.IndexReader; /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -59,14 +56,14 @@ public final class AdaptiveFacetsAccumulator extends StandardFacetsAccumulator { } /** - * Create an {@link AdaptiveFacetsAccumulator} - * @see StandardFacetsAccumulator#StandardFacetsAccumulator(FacetSearchParams, IndexReader, TaxonomyReader, - * IntArrayAllocator, FloatArrayAllocator) + * Create an {@link AdaptiveFacetsAccumulator} + * + * @see StandardFacetsAccumulator#StandardFacetsAccumulator(FacetSearchParams, + * IndexReader, TaxonomyReader, FacetArrays) */ public AdaptiveFacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader, - TaxonomyReader taxonomyReader, IntArrayAllocator intArrayAllocator, - FloatArrayAllocator floatArrayAllocator) { - super(searchParams, indexReader, taxonomyReader, intArrayAllocator, floatArrayAllocator); + TaxonomyReader taxonomyReader, FacetArrays facetArrays) { + super(searchParams, indexReader, taxonomyReader, facetArrays); } /** diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/ArraysPool.java b/lucene/facet/src/java/org/apache/lucene/facet/search/ArraysPool.java new file mode 100644 index 00000000000..69c8af30348 --- /dev/null +++ b/lucene/facet/src/java/org/apache/lucene/facet/search/ArraysPool.java @@ -0,0 +1,110 @@ +package org.apache.lucene.facet.search; + +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; + +/* + * 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. + */ + +/** + * A thread-safe pool of {@code int[]} and {@code float[]} arrays. One specifies + * the maximum number of arrays in the constructor. Calls to + * {@link #allocateFloatArray()} or {@link #allocateIntArray()} take an array + * from the pool, and if one is not available, allocate a new one. When you are + * done using the array, you should {@link #free(int[]) free} it. + *
+ * This class is used by {@link ReusingFacetArrays} for temporal facet
+ * aggregation arrays, which can be reused across searches instead of being
+ * allocated afresh on every search.
+ *
+ * @lucene.experimental
+ */
+public final class ArraysPool {
+
+ private final ArrayBlockingQueue
+ * NOTE: if you need to reuse the allocated arrays between search
+ * requests, use {@link ReusingFacetArrays}.
+ *
+ *
+ * NOTE: this class is not thread safe. You typically allocate it per
+ * search.
*
* @lucene.experimental
*/
public class FacetArrays {
- private int[] intArray;
- private float[] floatArray;
- private IntArrayAllocator intArrayAllocator;
- private FloatArrayAllocator floatArrayAllocator;
- private int arraysLength;
+ private int[] ints;
+ private float[] floats;
+
+ public final int arrayLength;
+ /** Arrays will be allocated at the specified length. */
+ public FacetArrays(int arrayLength) {
+ this.arrayLength = arrayLength;
+ }
+
+ protected float[] newFloatArray() {
+ return new float[arrayLength];
+ }
+
+ protected int[] newIntArray() {
+ return new int[arrayLength];
+ }
+
+ protected void doFree(float[] floats, int[] ints) {
+ }
+
/**
- * Create a FacetArrays with certain array allocators.
- * @param intArrayAllocator allocator for int arrays.
- * @param floatArrayAllocator allocator for float arrays.
+ * Notifies that the arrays obtained from {@link #getIntArray()}
+ * or {@link #getFloatArray()} are no longer needed and can be freed.
*/
- public FacetArrays(IntArrayAllocator intArrayAllocator,
- FloatArrayAllocator floatArrayAllocator) {
- this.intArrayAllocator = intArrayAllocator;
- this.floatArrayAllocator = floatArrayAllocator;
+ public final void free() {
+ doFree(floats, ints);
+ ints = null;
+ floats = null;
}
- /**
- * Notify allocators that they can free arrays allocated
- * on behalf of this FacetArrays object.
- */
- public void free() {
- if (intArrayAllocator!=null) {
- intArrayAllocator.free(intArray);
- // Should give up handle to the array now
- // that it is freed.
- intArray = null;
+ public final int[] getIntArray() {
+ if (ints == null) {
+ ints = newIntArray();
}
- if (floatArrayAllocator!=null) {
- floatArrayAllocator.free(floatArray);
- // Should give up handle to the array now
- // that it is freed.
- floatArray = null;
+ return ints;
+ }
+
+ public final float[] getFloatArray() {
+ if (floats == null) {
+ floats = newFloatArray();
}
- arraysLength = 0;
+ return floats;
}
- /**
- * Obtain an int array, e.g. for facet counting.
- */
- public int[] getIntArray() {
- if (intArray == null) {
- intArray = intArrayAllocator.allocate();
- arraysLength = intArray.length;
- }
- return intArray;
- }
-
- /** Obtain a float array, e.g. for evaluating facet association values. */
- public float[] getFloatArray() {
- if (floatArray == null) {
- floatArray = floatArrayAllocator.allocate();
- arraysLength = floatArray.length;
- }
- return floatArray;
- }
-
- /**
- * Return the arrays length
- */
- public int getArraysLength() {
- return arraysLength;
- }
-
-}
\ No newline at end of file
+}
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/FacetResultsHandler.java b/lucene/facet/src/java/org/apache/lucene/facet/search/FacetResultsHandler.java
index 314329c7e40..9422dceb63e 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/search/FacetResultsHandler.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/search/FacetResultsHandler.java
@@ -154,7 +154,7 @@ public abstract class FacetResultsHandler {
* offset in input arrays where partition starts
*/
protected boolean isSelfPartition (int ordinal, FacetArrays facetArrays, int offset) {
- int partitionSize = facetArrays.getArraysLength();
+ int partitionSize = facetArrays.arrayLength;
return ordinal / partitionSize == offset / partitionSize;
}
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/FloatArrayAllocator.java b/lucene/facet/src/java/org/apache/lucene/facet/search/FloatArrayAllocator.java
deleted file mode 100644
index 7c7e829c9e6..00000000000
--- a/lucene/facet/src/java/org/apache/lucene/facet/search/FloatArrayAllocator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.lucene.facet.search;
-
-import java.util.Arrays;
-
-/*
- * 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.
- */
-
-/**
- * An FloatArrayAllocator is an object which manages float array objects
- * of a certain size. These float arrays are needed temporarily during
- * faceted search (see {@link FacetsAccumulator} and can be reused across searches
- * instead of being allocated afresh on every search.
- *
- * An FloatArrayAllocator is thread-safe.
- *
- * @lucene.experimental
- */
-public final class FloatArrayAllocator extends TemporaryObjectAllocator
- * Note that the pool size only restricts the number of arrays that hang
- * around when not needed, but not the maximum number of arrays
- * that are allocated when actually is use: If a number of concurrent
- * threads ask for an allocation, all of them will get a counter array,
- * even if their number is greater than maxArrays. If an application wants
- * to limit the number of concurrent threads making allocations, it needs
- * to do so on its own - for example by blocking new threads until the
- * existing ones have finished.
- *
- * In particular, when maxArrays=0, this object behaves as a trivial
- * allocator, always allocating a new array and never reusing an old one.
- */
- public FloatArrayAllocator(int size, int maxArrays) {
- super(maxArrays);
- this.size = size;
- }
-
- @Override
- public float[] create() {
- return new float[size];
- }
-
- @Override
- public void clear(float[] array) {
- Arrays.fill(array, 0);
- }
-
-}
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/IntArrayAllocator.java b/lucene/facet/src/java/org/apache/lucene/facet/search/IntArrayAllocator.java
deleted file mode 100644
index 555d644ecb2..00000000000
--- a/lucene/facet/src/java/org/apache/lucene/facet/search/IntArrayAllocator.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.lucene.facet.search;
-
-import java.util.Arrays;
-
-/*
- * 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.
- */
-
-/**
- * An IntArrayAllocator is an object which manages counter array objects
- * of a certain length. These counter arrays are needed temporarily during
- * faceted search (see {@link FacetsAccumulator} and can be reused across searches
- * instead of being allocated afresh on every search.
- *
- * An IntArrayAllocator is thread-safe.
- *
- * @lucene.experimental
- */
-public final class IntArrayAllocator extends TemporaryObjectAllocator
- * Note that the pool size only restricts the number of arrays that hang
- * around when not needed, but not the maximum number of arrays
- * that are allocated when actually is use: If a number of concurrent
- * threads ask for an allocation, all of them will get a counter array,
- * even if their number is greater than maxArrays. If an application wants
- * to limit the number of concurrent threads making allocations, it needs
- * to do so on its own - for example by blocking new threads until the
- * existing ones have finished.
- *
- * In particular, when maxArrays=0, this object behaves as a trivial
- * allocator, always allocating a new array and never reusing an old one.
- */
- public IntArrayAllocator(int length, int maxArrays) {
- super(maxArrays);
- this.length = length;
- }
-
- @Override
- public int[] create() {
- return new int[length];
- }
-
- @Override
- public void clear(int[] array) {
- Arrays.fill(array, 0);
- }
-
-}
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/StandardFacetsAccumulator.java b/lucene/facet/src/java/org/apache/lucene/facet/search/StandardFacetsAccumulator.java
index 2df0975cce0..9d38942efe9 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/search/StandardFacetsAccumulator.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/search/StandardFacetsAccumulator.java
@@ -62,8 +62,7 @@ public class StandardFacetsAccumulator extends FacetsAccumulator {
private static final Logger logger = Logger.getLogger(StandardFacetsAccumulator.class.getName());
- protected final IntArrayAllocator intArrayAllocator;
- protected final FloatArrayAllocator floatArrayAllocator;
+ protected final FacetArrays facetArrays;
protected int partitionSize;
protected int maxPartitions;
@@ -74,20 +73,14 @@ public class StandardFacetsAccumulator extends FacetsAccumulator {
private Object accumulateGuard;
public StandardFacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader,
- TaxonomyReader taxonomyReader, IntArrayAllocator intArrayAllocator,
- FloatArrayAllocator floatArrayAllocator) {
-
+ TaxonomyReader taxonomyReader, FacetArrays facetArrays) {
super(searchParams,indexReader,taxonomyReader);
- int realPartitionSize = intArrayAllocator == null || floatArrayAllocator == null
- ? PartitionsUtils.partitionSize(searchParams, taxonomyReader) : -1; // -1 if not needed.
- this.intArrayAllocator = intArrayAllocator != null
- ? intArrayAllocator
- // create a default one if null was provided
- : new IntArrayAllocator(realPartitionSize, 1);
- this.floatArrayAllocator = floatArrayAllocator != null
- ? floatArrayAllocator
- // create a default one if null provided
- : new FloatArrayAllocator(realPartitionSize, 1);
+
+ if (facetArrays == null) {
+ throw new IllegalArgumentException("facetArrays cannot be null");
+ }
+
+ this.facetArrays = facetArrays;
// can only be computed later when docids size is known
isUsingComplements = false;
partitionSize = PartitionsUtils.partitionSize(searchParams, taxonomyReader);
@@ -95,10 +88,10 @@ public class StandardFacetsAccumulator extends FacetsAccumulator {
accumulateGuard = new Object();
}
- public StandardFacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader,
- TaxonomyReader taxonomyReader) {
-
- this(searchParams, indexReader, taxonomyReader, null, null);
+ public StandardFacetsAccumulator(FacetSearchParams searchParams,
+ IndexReader indexReader, TaxonomyReader taxonomyReader) {
+ this(searchParams, indexReader, taxonomyReader, new FacetArrays(
+ PartitionsUtils.partitionSize(searchParams, taxonomyReader)));
}
@Override
@@ -152,8 +145,6 @@ public class StandardFacetsAccumulator extends FacetsAccumulator {
docids = actualDocsToAccumulate(docids);
- FacetArrays facetArrays = new FacetArrays(intArrayAllocator, floatArrayAllocator);
-
HashMap
- * This technique is useful for temporary counter arrays in faceted search
- * (see {@link FacetsAccumulator}), which can be reused across searches instead
- * of being allocated afresh on every search.
- *
- * A TemporaryObjectAllocator is thread-safe.
- *
- * @lucene.experimental
- */
-public abstract class TemporaryObjectAllocator
- * Note that the pool size only restricts the number of objects that hang
- * around when not needed, but not the maximum number of objects
- * that are allocated when actually is use: If a number of concurrent
- * threads ask for an allocation, all of them will get an object, even if
- * their number is greater than maxObjects. If an application wants to
- * limit the number of concurrent threads making allocations, it needs to
- * do so on its own - for example by blocking new threads until the
- * existing ones have finished. If more than maxObjects are freed, only
- * maxObjects of them will be kept in the pool - the rest will not and
- * will eventually be garbage-collected by Java.
- *
- * In particular, when maxObjects=0, this object behaves as a trivial
- * allocator, always allocating a new array and never reusing an old one.
- */
- public TemporaryObjectAllocator(int maxObjects) {
- this.maxObjects = maxObjects;
- }
-
- /**
- * Subclasses must override this method to actually create a new object
- * of the desired type.
- *
- */
- protected abstract T create();
-
- /**
- * Subclasses must override this method to clear an existing object of
- * the desired type, to prepare it for reuse. Note that objects will be
- * cleared just before reuse (on allocation), not when freed.
- */
- protected abstract void clear(T object);
-
- /**
- * Allocate a new object. If there's a previously allocated object in our
- * pool, we return it immediately. Otherwise, a new object is allocated.
- *
- * Don't forget to call {@link #free(Object)} when you're done with the object,
- * to return it to the pool. If you don't, memory is not leaked,
- * but the pool will remain empty and a new object will be allocated each
- * time (just like the maxArrays=0 case).
- */
- public final T allocate() {
- T object = pool.poll();
- if (object==null) {
- return create();
- }
- clear(object);
- return object;
- }
-
- /**
- * Return a no-longer-needed object back to the pool. If we already have
- * enough objects in the pool (maxObjects as specified in the constructor),
- * the array will not be saved, and Java will eventually garbage collect
- * it.
- *
- * In particular, when maxArrays=0, the given array is never saved and
- * free does nothing.
- */
- public final void free(T object) {
- if (pool.size() < maxObjects && object != null) {
- pool.add(object);
- }
- }
-
-}
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/TopKFacetResultsHandler.java b/lucene/facet/src/java/org/apache/lucene/facet/search/TopKFacetResultsHandler.java
index a9755f54917..20feeb03c45 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/search/TopKFacetResultsHandler.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/search/TopKFacetResultsHandler.java
@@ -59,7 +59,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
if (ordinal != TaxonomyReader.INVALID_ORDINAL) {
double value = 0;
if (isSelfPartition(ordinal, facetArrays, offset)) {
- int partitionSize = facetArrays.getArraysLength();
+ int partitionSize = facetArrays.arrayLength;
value = facetRequest.getValueOf(facetArrays, ordinal % partitionSize);
}
@@ -121,7 +121,7 @@ public class TopKFacetResultsHandler extends FacetResultsHandler {
*/
private int heapDescendants(int ordinal, Heapsize
,
- * keeping around a pool of up to maxArrays
old arrays.
- * length
,
- * keeping around a pool of up to maxArrays
old arrays.
- * maxObjects
old objects.
- *