diff --git a/src/main/java/org/elasticsearch/common/util/AbstractArray.java b/src/main/java/org/elasticsearch/common/util/AbstractArray.java index c63467c453e..ba13ff39201 100644 --- a/src/main/java/org/elasticsearch/common/util/AbstractArray.java +++ b/src/main/java/org/elasticsearch/common/util/AbstractArray.java @@ -19,21 +19,26 @@ package org.elasticsearch.common.util; -import org.elasticsearch.common.lease.Releasable; -abstract class AbstractArray implements Releasable { +abstract class AbstractArray implements BigArray { + private final BigArrays bigArrays; public final boolean clearOnResize; private boolean released = false; - AbstractArray(boolean clearOnResize) { + AbstractArray(BigArrays bigArrays, boolean clearOnResize) { + this.bigArrays = bigArrays; this.clearOnResize = clearOnResize; } @Override - public void close() { + public final void close() { + bigArrays.ramBytesUsed.addAndGet(-sizeInBytes()); assert !released : "double release"; released = true; + doClose(); } + protected abstract void doClose(); + } diff --git a/src/main/java/org/elasticsearch/common/util/AbstractBigArray.java b/src/main/java/org/elasticsearch/common/util/AbstractBigArray.java index 6f8321247ab..18e0feaf5fa 100644 --- a/src/main/java/org/elasticsearch/common/util/AbstractBigArray.java +++ b/src/main/java/org/elasticsearch/common/util/AbstractBigArray.java @@ -32,6 +32,8 @@ import java.util.Arrays; /** Common implementation for array lists that slice data into fixed-size blocks. */ abstract class AbstractBigArray extends AbstractArray { + private static final long EMPTY_SIZE = RamUsageEstimator.shallowSizeOfInstance(AbstractBigArray.class) + RamUsageEstimator.NUM_BYTES_OBJECT_REF + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER; + private final PageCacheRecycler recycler; private Recycler.V[] cache; @@ -39,9 +41,9 @@ abstract class AbstractBigArray extends AbstractArray { private final int pageMask; protected long size; - protected AbstractBigArray(int pageSize, PageCacheRecycler recycler, boolean clearOnResize) { - super(clearOnResize); - this.recycler = recycler; + protected AbstractBigArray(int pageSize, BigArrays bigArrays, boolean clearOnResize) { + super(bigArrays, clearOnResize); + this.recycler = bigArrays.recycler; Preconditions.checkArgument(pageSize >= 128, "pageSize must be >= 128"); Preconditions.checkArgument((pageSize & (pageSize - 1)) == 0, "pageSize must be a power of two"); this.pageShift = Integer.numberOfTrailingZeros(pageSize); @@ -76,6 +78,8 @@ abstract class AbstractBigArray extends AbstractArray { return size; } + public abstract void resize(long newSize); + protected abstract int numBytesPerElement(); public final long sizeInBytes() { @@ -161,8 +165,7 @@ abstract class AbstractBigArray extends AbstractArray { } @Override - public final void close() { - super.close(); + protected final void doClose() { if (recycler != null) { Releasables.close(cache); cache = null; diff --git a/src/main/java/org/elasticsearch/common/util/BigArray.java b/src/main/java/org/elasticsearch/common/util/BigArray.java index 70b525e05aa..e6949249c7b 100644 --- a/src/main/java/org/elasticsearch/common/util/BigArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigArray.java @@ -27,4 +27,9 @@ public interface BigArray extends Releasable { /** Return the length of this array. */ public long size(); + /** + * Return an estimated memory usage of this instance. + */ + public long sizeInBytes(); + } diff --git a/src/main/java/org/elasticsearch/common/util/BigArrays.java b/src/main/java/org/elasticsearch/common/util/BigArrays.java index dcd2bf011bf..2d55599f4ce 100644 --- a/src/main/java/org/elasticsearch/common/util/BigArrays.java +++ b/src/main/java/org/elasticsearch/common/util/BigArrays.java @@ -23,6 +23,7 @@ import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.RamUsageEstimator; +import org.elasticsearch.ElasticsearchIllegalStateException; import org.elasticsearch.cache.recycler.PageCacheRecycler; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; @@ -33,11 +34,14 @@ import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; /** Utility class to work with arrays. */ public class BigArrays extends AbstractComponent { - public static final BigArrays NON_RECYCLING_INSTANCE = new BigArrays(ImmutableSettings.EMPTY, null); + // TODO: switch to a circuit breaker that is shared not only on big arrays level, and applies to other request level data structures + public static final String MAX_SIZE_IN_BYTES_SETTING = "requests.memory.breaker.limit"; + public static final BigArrays NON_RECYCLING_INSTANCE = new BigArrays(ImmutableSettings.EMPTY, null, Long.MAX_VALUE); /** Page size in bytes: 16KB */ public static final int PAGE_SIZE_IN_BYTES = 1 << 14; @@ -80,13 +84,15 @@ public class BigArrays extends AbstractComponent { return index == (int) index; } - private static abstract class AbstractArrayWrapper extends AbstractArray { + private static abstract class AbstractArrayWrapper extends AbstractArray implements BigArray { + + protected static final long SHALLOW_SIZE = RamUsageEstimator.shallowSizeOfInstance(ByteArrayWrapper.class); private final Releasable releasable; private final long size; - AbstractArrayWrapper(long size, Releasable releasable, boolean clearOnResize) { - super(clearOnResize); + AbstractArrayWrapper(BigArrays bigArrays, long size, Releasable releasable, boolean clearOnResize) { + super(bigArrays, clearOnResize); this.releasable = releasable; this.size = size; } @@ -96,7 +102,7 @@ public class BigArrays extends AbstractComponent { } @Override - public final void close() { + protected final void doClose() { Releasables.close(releasable); } @@ -106,11 +112,16 @@ public class BigArrays extends AbstractComponent { private final byte[] array; - ByteArrayWrapper(byte[] array, long size, Recycler.V releasable, boolean clearOnResize) { - super(size, releasable, clearOnResize); + ByteArrayWrapper(BigArrays bigArrays, byte[] array, long size, Recycler.V releasable, boolean clearOnResize) { + super(bigArrays, size, releasable, clearOnResize); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.sizeOf(array); + } + @Override public byte get(long index) { assert indexIsInt(index); @@ -152,11 +163,16 @@ public class BigArrays extends AbstractComponent { private final int[] array; - IntArrayWrapper(int[] array, long size, Recycler.V releasable, boolean clearOnResize) { - super(size, releasable, clearOnResize); + IntArrayWrapper(BigArrays bigArrays, int[] array, long size, Recycler.V releasable, boolean clearOnResize) { + super(bigArrays, size, releasable, clearOnResize); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.sizeOf(array); + } + @Override public int get(long index) { assert indexIsInt(index); @@ -190,11 +206,16 @@ public class BigArrays extends AbstractComponent { private final long[] array; - LongArrayWrapper(long[] array, long size, Recycler.V releasable, boolean clearOnResize) { - super(size, releasable, clearOnResize); + LongArrayWrapper(BigArrays bigArrays, long[] array, long size, Recycler.V releasable, boolean clearOnResize) { + super(bigArrays, size, releasable, clearOnResize); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.sizeOf(array); + } + @Override public long get(long index) { assert indexIsInt(index); @@ -227,11 +248,16 @@ public class BigArrays extends AbstractComponent { private final double[] array; - DoubleArrayWrapper(double[] array, long size, Recycler.V releasable, boolean clearOnResize) { - super(size, releasable, clearOnResize); + DoubleArrayWrapper(BigArrays bigArrays, double[] array, long size, Recycler.V releasable, boolean clearOnResize) { + super(bigArrays, size, releasable, clearOnResize); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.sizeOf(array); + } + @Override public double get(long index) { assert indexIsInt(index); @@ -265,11 +291,16 @@ public class BigArrays extends AbstractComponent { private final float[] array; - FloatArrayWrapper(float[] array, long size, Recycler.V releasable, boolean clearOnResize) { - super(size, releasable, clearOnResize); + FloatArrayWrapper(BigArrays bigArrays, float[] array, long size, Recycler.V releasable, boolean clearOnResize) { + super(bigArrays, size, releasable, clearOnResize); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.sizeOf(array); + } + @Override public float get(long index) { assert indexIsInt(index); @@ -303,11 +334,16 @@ public class BigArrays extends AbstractComponent { private final Object[] array; - ObjectArrayWrapper(Object[] array, long size, Recycler.V releasable) { - super(size, releasable, true); + ObjectArrayWrapper(BigArrays bigArrays, Object[] array, long size, Recycler.V releasable) { + super(bigArrays, size, releasable, true); this.array = array; } + @Override + public long sizeInBytes() { + return SHALLOW_SIZE + RamUsageEstimator.alignObjectSize(RamUsageEstimator.NUM_BYTES_ARRAY_HEADER + RamUsageEstimator.NUM_BYTES_OBJECT_REF * size()); + } + @SuppressWarnings("unchecked") @Override public T get(long index) { @@ -327,11 +363,46 @@ public class BigArrays extends AbstractComponent { } final PageCacheRecycler recycler; + final AtomicLong ramBytesUsed; + final long maxSizeInBytes; @Inject public BigArrays(Settings settings, PageCacheRecycler recycler) { + this(settings, recycler, settings.getAsMemory(MAX_SIZE_IN_BYTES_SETTING, "20%").bytes()); + } + + private BigArrays(Settings settings, PageCacheRecycler recycler, final long maxSizeInBytes) { super(settings); + this.maxSizeInBytes = maxSizeInBytes; this.recycler = recycler; + ramBytesUsed = new AtomicLong(); + } + + private void validate(long delta) { + final long totalSizeInBytes = ramBytesUsed.addAndGet(delta); + if (totalSizeInBytes > maxSizeInBytes) { + throw new ElasticsearchIllegalStateException("Maximum number of bytes allocated exceeded: [" + totalSizeInBytes + "] (> " + maxSizeInBytes + ")"); + } + } + + private T resizeInPlace(T array, long newSize) { + final long oldMemSize = array.sizeInBytes(); + array.resize(newSize); + validate(array.sizeInBytes() - oldMemSize); + return array; + } + + private T validate(T array) { + boolean success = false; + try { + validate(array.sizeInBytes()); + success = true; + } finally { + if (!success) { + Releasables.closeWhileHandlingException(array); + } + } + return array; } /** @@ -340,14 +411,16 @@ public class BigArrays extends AbstractComponent { * @param clearOnResize whether values should be set to 0 on initialization and resize */ public ByteArray newByteArray(long size, boolean clearOnResize) { + final ByteArray array; if (size > BYTE_PAGE_SIZE) { - return new BigByteArray(size, recycler, clearOnResize); + array = new BigByteArray(size, this, clearOnResize); } else if (size >= BYTE_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.bytePage(clearOnResize); - return new ByteArrayWrapper(page.v(), size, page, clearOnResize); + array = new ByteArrayWrapper(this, page.v(), size, page, clearOnResize); } else { - return new ByteArrayWrapper(new byte[(int) size], size, null, clearOnResize); + array = new ByteArrayWrapper(this, new byte[(int) size], size, null, clearOnResize); } + return validate(array); } /** @@ -361,14 +434,13 @@ public class BigArrays extends AbstractComponent { /** Resize the array to the exact provided size. */ public ByteArray resize(ByteArray array, long size) { if (array instanceof BigByteArray) { - ((BigByteArray) array).resize(size); - return array; + return resizeInPlace((BigByteArray) array, size); } else { AbstractArray arr = (AbstractArray) array; final ByteArray newArray = newByteArray(size, arr.clearOnResize); final byte[] rawArray = ((ByteArrayWrapper) array).array; newArray.set(0, rawArray, 0, (int) Math.min(rawArray.length, newArray.size())); - array.close(); + arr.close(); return newArray; } } @@ -421,14 +493,16 @@ public class BigArrays extends AbstractComponent { * @param clearOnResize whether values should be set to 0 on initialization and resize */ public IntArray newIntArray(long size, boolean clearOnResize) { + final IntArray array; if (size > INT_PAGE_SIZE) { - return new BigIntArray(size, recycler, clearOnResize); + array = new BigIntArray(size, this, clearOnResize); } else if (size >= INT_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.intPage(clearOnResize); - return new IntArrayWrapper(page.v(), size, page, clearOnResize); + array = new IntArrayWrapper(this, page.v(), size, page, clearOnResize); } else { - return new IntArrayWrapper(new int[(int) size], size, null, clearOnResize); + array = new IntArrayWrapper(this, new int[(int) size], size, null, clearOnResize); } + return validate(array); } /** @@ -442,8 +516,7 @@ public class BigArrays extends AbstractComponent { /** Resize the array to the exact provided size. */ public IntArray resize(IntArray array, long size) { if (array instanceof BigIntArray) { - ((BigIntArray) array).resize(size); - return array; + return resizeInPlace((BigIntArray) array, size); } else { AbstractArray arr = (AbstractArray) array; final IntArray newArray = newIntArray(size, arr.clearOnResize); @@ -470,14 +543,16 @@ public class BigArrays extends AbstractComponent { * @param clearOnResize whether values should be set to 0 on initialization and resize */ public LongArray newLongArray(long size, boolean clearOnResize) { + final LongArray array; if (size > LONG_PAGE_SIZE) { - return new BigLongArray(size, recycler, clearOnResize); + array = new BigLongArray(size, this, clearOnResize); } else if (size >= LONG_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.longPage(clearOnResize); - return new LongArrayWrapper(page.v(), size, page, clearOnResize); + array = new LongArrayWrapper(this, page.v(), size, page, clearOnResize); } else { - return new LongArrayWrapper(new long[(int) size], size, null, clearOnResize); + array = new LongArrayWrapper(this, new long[(int) size], size, null, clearOnResize); } + return validate(array); } /** @@ -491,8 +566,7 @@ public class BigArrays extends AbstractComponent { /** Resize the array to the exact provided size. */ public LongArray resize(LongArray array, long size) { if (array instanceof BigLongArray) { - ((BigLongArray) array).resize(size); - return array; + return resizeInPlace((BigLongArray) array, size); } else { AbstractArray arr = (AbstractArray) array; final LongArray newArray = newLongArray(size, arr.clearOnResize); @@ -519,14 +593,16 @@ public class BigArrays extends AbstractComponent { * @param clearOnResize whether values should be set to 0 on initialization and resize */ public DoubleArray newDoubleArray(long size, boolean clearOnResize) { + final DoubleArray arr; if (size > DOUBLE_PAGE_SIZE) { - return new BigDoubleArray(size, recycler, clearOnResize); + arr = new BigDoubleArray(size, this, clearOnResize); } else if (size >= DOUBLE_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.doublePage(clearOnResize); - return new DoubleArrayWrapper(page.v(), size, page, clearOnResize); + arr = new DoubleArrayWrapper(this, page.v(), size, page, clearOnResize); } else { - return new DoubleArrayWrapper(new double[(int) size], size, null, clearOnResize); + arr = new DoubleArrayWrapper(this, new double[(int) size], size, null, clearOnResize); } + return validate(arr); } /** Allocate a new {@link DoubleArray} of the given capacity. */ @@ -537,8 +613,7 @@ public class BigArrays extends AbstractComponent { /** Resize the array to the exact provided size. */ public DoubleArray resize(DoubleArray array, long size) { if (array instanceof BigDoubleArray) { - ((BigDoubleArray) array).resize(size); - return array; + return resizeInPlace((BigDoubleArray) array, size); } else { AbstractArray arr = (AbstractArray) array; final DoubleArray newArray = newDoubleArray(size, arr.clearOnResize); @@ -565,14 +640,16 @@ public class BigArrays extends AbstractComponent { * @param clearOnResize whether values should be set to 0 on initialization and resize */ public FloatArray newFloatArray(long size, boolean clearOnResize) { + final FloatArray array; if (size > FLOAT_PAGE_SIZE) { - return new BigFloatArray(size, recycler, clearOnResize); + array = new BigFloatArray(size, this, clearOnResize); } else if (size >= FLOAT_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.floatPage(clearOnResize); - return new FloatArrayWrapper(page.v(), size, page, clearOnResize); + array = new FloatArrayWrapper(this, page.v(), size, page, clearOnResize); } else { - return new FloatArrayWrapper(new float[(int) size], size, null, clearOnResize); + array = new FloatArrayWrapper(this, new float[(int) size], size, null, clearOnResize); } + return validate(array); } /** Allocate a new {@link FloatArray} of the given capacity. */ @@ -583,14 +660,14 @@ public class BigArrays extends AbstractComponent { /** Resize the array to the exact provided size. */ public FloatArray resize(FloatArray array, long size) { if (array instanceof BigFloatArray) { - ((BigFloatArray) array).resize(size); - return array; + return resizeInPlace((BigFloatArray) array, size); } else { AbstractArray arr = (AbstractArray) array; final FloatArray newArray = newFloatArray(size, arr.clearOnResize); for (long i = 0, end = Math.min(size, array.size()); i < end; ++i) { newArray.set(i, array.get(i)); } + arr.close(); return newArray; } } @@ -609,21 +686,22 @@ public class BigArrays extends AbstractComponent { * @param size the initial length of the array */ public ObjectArray newObjectArray(long size) { + final ObjectArray array; if (size > OBJECT_PAGE_SIZE) { - return new BigObjectArray<>(size, recycler); + array = new BigObjectArray<>(size, this); } else if (size >= OBJECT_PAGE_SIZE / 2 && recycler != null) { final Recycler.V page = recycler.objectPage(); - return new ObjectArrayWrapper<>(page.v(), size, page); + array = new ObjectArrayWrapper<>(this, page.v(), size, page); } else { - return new ObjectArrayWrapper<>(new Object[(int) size], size, null); + array = new ObjectArrayWrapper<>(this, new Object[(int) size], size, null); } + return validate(array); } /** Resize the array to the exact provided size. */ public ObjectArray resize(ObjectArray array, long size) { if (array instanceof BigObjectArray) { - ((BigObjectArray) array).resize(size); - return array; + return resizeInPlace((BigObjectArray) array, size); } else { final ObjectArray newArray = newObjectArray(size); for (long i = 0, end = Math.min(size, array.size()); i < end; ++i) { @@ -643,4 +721,10 @@ public class BigArrays extends AbstractComponent { return resize(array, newSize); } + /** + * Return an approximate number of bytes that have been allocated but not released yet. + */ + public long sizeInBytes() { + return ramBytesUsed.get(); + } } diff --git a/src/main/java/org/elasticsearch/common/util/BigByteArray.java b/src/main/java/org/elasticsearch/common/util/BigByteArray.java index 405dd78808e..539254fa351 100644 --- a/src/main/java/org/elasticsearch/common/util/BigByteArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigByteArray.java @@ -23,7 +23,6 @@ import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -38,15 +37,15 @@ final class BigByteArray extends AbstractBigArray implements ByteArray { private byte[][] pages; /** Constructor. */ - public BigByteArray(long size, PageCacheRecycler recycler, boolean clearOnResize) { - super(BYTE_PAGE_SIZE, recycler, clearOnResize); + public BigByteArray(long size, BigArrays bigArrays, boolean clearOnResize) { + super(BYTE_PAGE_SIZE, bigArrays, clearOnResize); this.size = size; pages = new byte[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { pages[i] = newBytePage(i); } } - + @Override public byte get(long index) { final int pageIndex = pageIndex(index); diff --git a/src/main/java/org/elasticsearch/common/util/BigDoubleArray.java b/src/main/java/org/elasticsearch/common/util/BigDoubleArray.java index e39b38f8bc7..4f6818acef5 100644 --- a/src/main/java/org/elasticsearch/common/util/BigDoubleArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigDoubleArray.java @@ -22,7 +22,6 @@ package org.elasticsearch.common.util; import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -37,8 +36,8 @@ final class BigDoubleArray extends AbstractBigArray implements DoubleArray { private double[][] pages; /** Constructor. */ - public BigDoubleArray(long size, PageCacheRecycler recycler, boolean clearOnResize) { - super(DOUBLE_PAGE_SIZE, recycler, clearOnResize); + public BigDoubleArray(long size, BigArrays bigArrays, boolean clearOnResize) { + super(DOUBLE_PAGE_SIZE, bigArrays, clearOnResize); this.size = size; pages = new double[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { diff --git a/src/main/java/org/elasticsearch/common/util/BigDoubleArrayList.java b/src/main/java/org/elasticsearch/common/util/BigDoubleArrayList.java deleted file mode 100644 index 662d465d10d..00000000000 --- a/src/main/java/org/elasticsearch/common/util/BigDoubleArrayList.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.common.util; - -import org.apache.lucene.util.ArrayUtil; -import org.apache.lucene.util.RamUsageEstimator; - -import java.util.Arrays; - -/** - * Float array abstraction able to support more than 2B values. This implementation slices data into fixed-sized blocks of - * configurable length. - */ -public final class BigDoubleArrayList extends AbstractBigArray { - - /** - * Default page size, 16KB of memory per page. - */ - private static final int DEFAULT_PAGE_SIZE = 1 << 11; - - private double[][] pages; - - public BigDoubleArrayList(int pageSize, long initialCapacity) { - super(pageSize, null, true); - pages = new double[numPages(initialCapacity)][]; - } - - public BigDoubleArrayList(long initialCapacity) { - this(DEFAULT_PAGE_SIZE, initialCapacity); - } - - public BigDoubleArrayList() { - this(1024); - } - - public double get(long index) { - assert index >= 0 && index < size; - final int pageIndex = pageIndex(index); - final int indexInPage = indexInPage(index); - return pages[pageIndex][indexInPage]; - } - - public void add(double d) { - final int pageIndex = pageIndex(size); - if (pageIndex >= pages.length) { - final int newLength = ArrayUtil.oversize(pageIndex + 1, numBytesPerElement()); - pages = Arrays.copyOf(pages, newLength); - } - if (pages[pageIndex] == null) { - pages[pageIndex] = new double[pageSize()]; - } - final int indexInPage = indexInPage(size); - pages[pageIndex][indexInPage] = d; - ++size; - } - - @Override - protected int numBytesPerElement() { - return RamUsageEstimator.NUM_BYTES_DOUBLE; - } - -} diff --git a/src/main/java/org/elasticsearch/common/util/BigFloatArray.java b/src/main/java/org/elasticsearch/common/util/BigFloatArray.java index fb807db93b7..98540ff12e8 100644 --- a/src/main/java/org/elasticsearch/common/util/BigFloatArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigFloatArray.java @@ -22,7 +22,6 @@ package org.elasticsearch.common.util; import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -37,8 +36,8 @@ final class BigFloatArray extends AbstractBigArray implements FloatArray { private float[][] pages; /** Constructor. */ - public BigFloatArray(long size, PageCacheRecycler recycler, boolean clearOnResize) { - super(FLOAT_PAGE_SIZE, recycler, clearOnResize); + public BigFloatArray(long size, BigArrays bigArrays, boolean clearOnResize) { + super(FLOAT_PAGE_SIZE, bigArrays, clearOnResize); this.size = size; pages = new float[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { diff --git a/src/main/java/org/elasticsearch/common/util/BigFloatArrayList.java b/src/main/java/org/elasticsearch/common/util/BigFloatArrayList.java deleted file mode 100644 index 732de87c284..00000000000 --- a/src/main/java/org/elasticsearch/common/util/BigFloatArrayList.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch 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.elasticsearch.common.util; - -import org.apache.lucene.util.ArrayUtil; -import org.apache.lucene.util.RamUsageEstimator; - -/** - * Float array abstraction able to support more than 2B values. This implementation slices data into fixed-sized blocks of - * configurable length. - */ -public final class BigFloatArrayList extends AbstractBigArray { - - /** - * Default page size, 16KB of memory per page. - */ - private static final int DEFAULT_PAGE_SIZE = 1 << 12; - - private float[][] pages; - - public BigFloatArrayList(int pageSize, long initialCapacity) { - super(pageSize, null, true); - pages = new float[numPages(initialCapacity)][]; - } - - public BigFloatArrayList(long initialCapacity) { - this(DEFAULT_PAGE_SIZE, initialCapacity); - } - - public BigFloatArrayList() { - this(1024); - } - - public float get(long index) { - assert index >= 0 && index < size; - final int pageIndex = pageIndex(index); - final int indexInPage = indexInPage(index); - return pages[pageIndex][indexInPage]; - } - - public void add(float f) { - final int pageIndex = pageIndex(size); - pages = ArrayUtil.grow(pages, pageIndex + 1); - if (pages[pageIndex] == null) { - pages[pageIndex] = new float[pageSize()]; - } - final int indexInPage = indexInPage(size); - pages[pageIndex][indexInPage] = f; - ++size; - } - - @Override - protected int numBytesPerElement() { - return RamUsageEstimator.NUM_BYTES_FLOAT; - } - -} diff --git a/src/main/java/org/elasticsearch/common/util/BigIntArray.java b/src/main/java/org/elasticsearch/common/util/BigIntArray.java index 52eb3e4f4e3..8e7098868a2 100644 --- a/src/main/java/org/elasticsearch/common/util/BigIntArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigIntArray.java @@ -22,7 +22,6 @@ package org.elasticsearch.common.util; import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -37,8 +36,8 @@ final class BigIntArray extends AbstractBigArray implements IntArray { private int[][] pages; /** Constructor. */ - public BigIntArray(long size, PageCacheRecycler recycler, boolean clearOnResize) { - super(INT_PAGE_SIZE, recycler, clearOnResize); + public BigIntArray(long size, BigArrays bigArrays, boolean clearOnResize) { + super(INT_PAGE_SIZE, bigArrays, clearOnResize); this.size = size; pages = new int[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { diff --git a/src/main/java/org/elasticsearch/common/util/BigLongArray.java b/src/main/java/org/elasticsearch/common/util/BigLongArray.java index d84b0436bf5..88dc8259b5d 100644 --- a/src/main/java/org/elasticsearch/common/util/BigLongArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigLongArray.java @@ -22,7 +22,6 @@ package org.elasticsearch.common.util; import com.google.common.base.Preconditions; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -37,8 +36,8 @@ final class BigLongArray extends AbstractBigArray implements LongArray { private long[][] pages; /** Constructor. */ - public BigLongArray(long size, PageCacheRecycler recycler, boolean clearOnResize) { - super(LONG_PAGE_SIZE, recycler, clearOnResize); + public BigLongArray(long size, BigArrays bigArrays, boolean clearOnResize) { + super(LONG_PAGE_SIZE, bigArrays, clearOnResize); this.size = size; pages = new long[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { diff --git a/src/main/java/org/elasticsearch/common/util/BigObjectArray.java b/src/main/java/org/elasticsearch/common/util/BigObjectArray.java index 9be9963a4d7..fe35571569f 100644 --- a/src/main/java/org/elasticsearch/common/util/BigObjectArray.java +++ b/src/main/java/org/elasticsearch/common/util/BigObjectArray.java @@ -21,7 +21,6 @@ package org.elasticsearch.common.util; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.cache.recycler.PageCacheRecycler; import java.util.Arrays; @@ -36,8 +35,8 @@ final class BigObjectArray extends AbstractBigArray implements ObjectArray private Object[][] pages; /** Constructor. */ - public BigObjectArray(long size, PageCacheRecycler recycler) { - super(OBJECT_PAGE_SIZE, recycler, true); + public BigObjectArray(long size, BigArrays bigArrays) { + super(OBJECT_PAGE_SIZE, bigArrays, true); this.size = size; pages = new Object[numPages(size)][]; for (int i = 0; i < pages.length; ++i) { diff --git a/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayAtomicFieldData.java b/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayAtomicFieldData.java index eb2e8713afe..c2a5425c4f1 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayAtomicFieldData.java +++ b/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayAtomicFieldData.java @@ -21,7 +21,7 @@ package org.elasticsearch.index.fielddata.plain; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.RamUsageEstimator; -import org.elasticsearch.common.util.BigDoubleArrayList; +import org.elasticsearch.common.util.DoubleArray; import org.elasticsearch.index.fielddata.*; import org.elasticsearch.index.fielddata.ordinals.Ordinals; @@ -87,10 +87,10 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi public static class WithOrdinals extends DoubleArrayAtomicFieldData { - private final BigDoubleArrayList values; + private final DoubleArray values; private final Ordinals ordinals; - public WithOrdinals(BigDoubleArrayList values, Ordinals ordinals) { + public WithOrdinals(DoubleArray values, Ordinals ordinals) { super(); this.values = values; this.ordinals = ordinals; @@ -128,9 +128,9 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static class LongValues extends org.elasticsearch.index.fielddata.LongValues.WithOrdinals { - private final BigDoubleArrayList values; + private final DoubleArray values; - LongValues(BigDoubleArrayList values, Ordinals.Docs ordinals) { + LongValues(DoubleArray values, Ordinals.Docs ordinals) { super(ordinals); this.values = values; } @@ -144,9 +144,9 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static class DoubleValues extends org.elasticsearch.index.fielddata.DoubleValues.WithOrdinals { - private final BigDoubleArrayList values; + private final DoubleArray values; - DoubleValues(BigDoubleArrayList values, Ordinals.Docs ordinals) { + DoubleValues(DoubleArray values, Ordinals.Docs ordinals) { super(ordinals); this.values = values; } @@ -165,11 +165,11 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi */ public static class SingleFixedSet extends DoubleArrayAtomicFieldData { - private final BigDoubleArrayList values; + private final DoubleArray values; private final FixedBitSet set; private final long numOrds; - public SingleFixedSet(BigDoubleArrayList values, FixedBitSet set, long numOrds) { + public SingleFixedSet(DoubleArray values, FixedBitSet set, long numOrds) { super(); this.values = values; this.set = set; @@ -206,10 +206,10 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static class LongValues extends org.elasticsearch.index.fielddata.LongValues { - private final BigDoubleArrayList values; + private final DoubleArray values; private final FixedBitSet set; - LongValues(BigDoubleArrayList values, FixedBitSet set) { + LongValues(DoubleArray values, FixedBitSet set) { super(false); this.values = values; this.set = set; @@ -229,10 +229,10 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static class DoubleValues extends org.elasticsearch.index.fielddata.DoubleValues { - private final BigDoubleArrayList values; + private final DoubleArray values; private final FixedBitSet set; - DoubleValues(BigDoubleArrayList values, FixedBitSet set) { + DoubleValues(DoubleArray values, FixedBitSet set) { super(false); this.values = values; this.set = set; @@ -256,14 +256,14 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi */ public static class Single extends DoubleArrayAtomicFieldData { - private final BigDoubleArrayList values; + private final DoubleArray values; private final long numOrds; /** * Note, here, we assume that there is no offset by 1 from docId, so position 0 * is the value for docId 0. */ - public Single(BigDoubleArrayList values, long numOrds) { + public Single(DoubleArray values, long numOrds) { super(); this.values = values; this.numOrds = numOrds; @@ -299,9 +299,9 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static final class LongValues extends DenseLongValues { - private final BigDoubleArrayList values; + private final DoubleArray values; - LongValues(BigDoubleArrayList values) { + LongValues(DoubleArray values) { super(false); this.values = values; } @@ -314,9 +314,9 @@ public abstract class DoubleArrayAtomicFieldData extends AbstractAtomicNumericFi static final class DoubleValues extends DenseDoubleValues { - private final BigDoubleArrayList values; + private final DoubleArray values; - DoubleValues(BigDoubleArrayList values) { + DoubleValues(DoubleArray values) { super(false); this.values = values; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayIndexFieldData.java b/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayIndexFieldData.java index 969a96ceeab..84e9b084b1d 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayIndexFieldData.java +++ b/src/main/java/org/elasticsearch/index/fielddata/plain/DoubleArrayIndexFieldData.java @@ -25,11 +25,11 @@ import org.apache.lucene.index.Terms; import org.apache.lucene.util.*; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.BigDoubleArrayList; +import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.common.util.DoubleArray; import org.elasticsearch.index.Index; import org.elasticsearch.index.fielddata.*; import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource; -import org.elasticsearch.search.MultiValueMode; import org.elasticsearch.index.fielddata.ordinals.GlobalOrdinalsBuilder; import org.elasticsearch.index.fielddata.ordinals.Ordinals; import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs; @@ -38,6 +38,7 @@ import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.settings.IndexSettings; import org.elasticsearch.indices.fielddata.breaker.CircuitBreakerService; +import org.elasticsearch.search.MultiValueMode; /** */ @@ -86,16 +87,19 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData ACQUIRED_ARRAYS = new ConcurrentHashMap<>(); public static void ensureAllArraysAreReleased() throws Exception { @@ -68,6 +69,12 @@ public class MockBigArrays extends BigArrays { } } } + if (INSTANCE != null) { + final long sizeInBytes = INSTANCE.sizeInBytes(); + if (sizeInBytes != 0) { + throw new AssertionError("Expected 0 bytes, got " + sizeInBytes); + } + } } private final Random random; @@ -82,6 +89,7 @@ public class MockBigArrays extends BigArrays { seed = 0; } random = new Random(seed); + INSTANCE = this; } @Override @@ -234,11 +242,13 @@ public class MockBigArrays extends BigArrays { private static abstract class AbstractArrayWrapper { + final BigArray in; boolean clearOnResize; AtomicBoolean released; - AbstractArrayWrapper(boolean clearOnResize) { + AbstractArrayWrapper(BigArray in, boolean clearOnResize) { ACQUIRED_ARRAYS.put(this, TRACK_ALLOCATIONS ? new RuntimeException() : Boolean.TRUE); + this.in = in; this.clearOnResize = clearOnResize; released = new AtomicBoolean(false); } @@ -251,6 +261,10 @@ public class MockBigArrays extends BigArrays { return getDelegate().size(); } + public long sizeInBytes() { + return in.sizeInBytes(); + } + public void close() { if (!released.compareAndSet(false, true)) { throw new IllegalStateException("Double release"); @@ -267,7 +281,7 @@ public class MockBigArrays extends BigArrays { private final ByteArray in; ByteArrayWrapper(ByteArray in, boolean clearOnResize) { - super(clearOnResize); + super(in, clearOnResize); this.in = in; } @@ -313,7 +327,7 @@ public class MockBigArrays extends BigArrays { private final IntArray in; IntArrayWrapper(IntArray in, boolean clearOnResize) { - super(clearOnResize); + super(in, clearOnResize); this.in = in; } @@ -354,7 +368,7 @@ public class MockBigArrays extends BigArrays { private final LongArray in; LongArrayWrapper(LongArray in, boolean clearOnResize) { - super(clearOnResize); + super(in, clearOnResize); this.in = in; } @@ -395,7 +409,7 @@ public class MockBigArrays extends BigArrays { private final FloatArray in; FloatArrayWrapper(FloatArray in, boolean clearOnResize) { - super(clearOnResize); + super(in, clearOnResize); this.in = in; } @@ -436,7 +450,7 @@ public class MockBigArrays extends BigArrays { private final DoubleArray in; DoubleArrayWrapper(DoubleArray in, boolean clearOnResize) { - super(clearOnResize); + super(in, clearOnResize); this.in = in; } @@ -477,7 +491,7 @@ public class MockBigArrays extends BigArrays { private final ObjectArray in; ObjectArrayWrapper(ObjectArray in) { - super(false); + super(in, false); this.in = in; }