123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /*
- * 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.BytesRef;
- import org.elasticsearch.cache.recycler.PageCacheRecycler;
- import org.elasticsearch.common.breaker.CircuitBreaker;
- import org.elasticsearch.common.breaker.CircuitBreakingException;
- import org.elasticsearch.common.settings.ImmutableSettings;
- import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
- import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
- import org.elasticsearch.node.settings.NodeSettingsService;
- import org.elasticsearch.test.ElasticsearchTestCase;
- import org.elasticsearch.test.cache.recycler.MockBigArrays;
- import org.elasticsearch.test.cache.recycler.MockPageCacheRecycler;
- import org.elasticsearch.threadpool.ThreadPool;
- import org.junit.Before;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.util.Arrays;
- public class BigArraysTests extends ElasticsearchTestCase {
- public static BigArrays randombigArrays() {
- final PageCacheRecycler recycler = randomBoolean() ? null : new MockPageCacheRecycler(ImmutableSettings.EMPTY, new ThreadPool("BigArraysTests"));
- return new MockBigArrays(ImmutableSettings.EMPTY, recycler, new NoneCircuitBreakerService());
- }
- private BigArrays bigArrays;
- @Before
- public void init() {
- bigArrays = randombigArrays();
- }
- public void testByteArrayGrowth() {
- final int totalLen = randomIntBetween(1, 4000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- ByteArray array = bigArrays.newByteArray(startLen, randomBoolean());
- byte[] ref = new byte[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomByte();
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertEquals(ref[i], array.get(i));
- }
- array.close();
- }
- public void testIntArrayGrowth() {
- final int totalLen = randomIntBetween(1, 1000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- IntArray array = bigArrays.newIntArray(startLen, randomBoolean());
- int[] ref = new int[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomInt();
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertEquals(ref[i], array.get(i));
- }
- array.close();
- }
- public void testLongArrayGrowth() {
- final int totalLen = randomIntBetween(1, 1000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- LongArray array = bigArrays.newLongArray(startLen, randomBoolean());
- long[] ref = new long[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomLong();
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertEquals(ref[i], array.get(i));
- }
- array.close();
- }
- public void testFloatArrayGrowth() {
- final int totalLen = randomIntBetween(1, 1000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- FloatArray array = bigArrays.newFloatArray(startLen, randomBoolean());
- float[] ref = new float[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomFloat();
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertEquals(ref[i], array.get(i), 0.001d);
- }
- array.close();
- }
- public void testDoubleArrayGrowth() {
- final int totalLen = randomIntBetween(1, 1000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- DoubleArray array = bigArrays.newDoubleArray(startLen, randomBoolean());
- double[] ref = new double[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomDouble();
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertEquals(ref[i], array.get(i), 0.001d);
- }
- array.close();
- }
- public void testObjectArrayGrowth() {
- final int totalLen = randomIntBetween(1, 1000000);
- final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
- ObjectArray<Object> array = bigArrays.newObjectArray(startLen);
- final Object[] pool = new Object[100];
- for (int i = 0; i < pool.length; ++i) {
- pool[i] = new Object();
- }
- Object[] ref = new Object[totalLen];
- for (int i = 0; i < totalLen; ++i) {
- ref[i] = randomFrom(pool);
- array = bigArrays.grow(array, i + 1);
- array.set(i, ref[i]);
- }
- for (int i = 0; i < totalLen; ++i) {
- assertSame(ref[i], array.get(i));
- }
- array.close();
- }
- public void testByteArrayFill() {
- final int len = randomIntBetween(1, 100000);
- final int fromIndex = randomIntBetween(0, len - 1);
- final int toIndex = randomBoolean()
- ? Math.min(fromIndex + randomInt(100), len) // single page
- : randomIntBetween(fromIndex, len); // likely multiple pages
- final ByteArray array2 = bigArrays.newByteArray(len, randomBoolean());
- final byte[] array1 = new byte[len];
- for (int i = 0; i < len; ++i) {
- array1[i] = randomByte();
- array2.set(i, array1[i]);
- }
- final byte rand = randomByte();
- Arrays.fill(array1, fromIndex, toIndex, rand);
- array2.fill(fromIndex, toIndex, rand);
- for (int i = 0; i < len; ++i) {
- assertEquals(array1[i], array2.get(i), 0.001d);
- }
- array2.close();
- }
- public void testFloatArrayFill() {
- final int len = randomIntBetween(1, 100000);
- final int fromIndex = randomIntBetween(0, len - 1);
- final int toIndex = randomBoolean()
- ? Math.min(fromIndex + randomInt(100), len) // single page
- : randomIntBetween(fromIndex, len); // likely multiple pages
- final FloatArray array2 = bigArrays.newFloatArray(len, randomBoolean());
- final float[] array1 = new float[len];
- for (int i = 0; i < len; ++i) {
- array1[i] = randomFloat();
- array2.set(i, array1[i]);
- }
- final float rand = randomFloat();
- Arrays.fill(array1, fromIndex, toIndex, rand);
- array2.fill(fromIndex, toIndex, rand);
- for (int i = 0; i < len; ++i) {
- assertEquals(array1[i], array2.get(i), 0.001d);
- }
- array2.close();
- }
- public void testDoubleArrayFill() {
- final int len = randomIntBetween(1, 100000);
- final int fromIndex = randomIntBetween(0, len - 1);
- final int toIndex = randomBoolean()
- ? Math.min(fromIndex + randomInt(100), len) // single page
- : randomIntBetween(fromIndex, len); // likely multiple pages
- final DoubleArray array2 = bigArrays.newDoubleArray(len, randomBoolean());
- final double[] array1 = new double[len];
- for (int i = 0; i < len; ++i) {
- array1[i] = randomDouble();
- array2.set(i, array1[i]);
- }
- final double rand = randomDouble();
- Arrays.fill(array1, fromIndex, toIndex, rand);
- array2.fill(fromIndex, toIndex, rand);
- for (int i = 0; i < len; ++i) {
- assertEquals(array1[i], array2.get(i), 0.001d);
- }
- array2.close();
- }
- public void testLongArrayFill() {
- final int len = randomIntBetween(1, 100000);
- final int fromIndex = randomIntBetween(0, len - 1);
- final int toIndex = randomBoolean()
- ? Math.min(fromIndex + randomInt(100), len) // single page
- : randomIntBetween(fromIndex, len); // likely multiple pages
- final LongArray array2 = bigArrays.newLongArray(len, randomBoolean());
- final long[] array1 = new long[len];
- for (int i = 0; i < len; ++i) {
- array1[i] = randomLong();
- array2.set(i, array1[i]);
- }
- final long rand = randomLong();
- Arrays.fill(array1, fromIndex, toIndex, rand);
- array2.fill(fromIndex, toIndex, rand);
- for (int i = 0; i < len; ++i) {
- assertEquals(array1[i], array2.get(i));
- }
- array2.close();
- }
- public void testByteArrayBulkGet() {
- final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
- getRandom().nextBytes(array1);
- final ByteArray array2 = bigArrays.newByteArray(array1.length, randomBoolean());
- for (int i = 0; i < array1.length; ++i) {
- array2.set(i, array1[i]);
- }
- final BytesRef ref = new BytesRef();
- for (int i = 0; i < 1000; ++i) {
- final int offset = randomInt(array1.length - 1);
- final int len = randomInt(Math.min(randomBoolean() ? 10 : Integer.MAX_VALUE, array1.length - offset));
- array2.get(offset, len, ref);
- assertEquals(new BytesRef(array1, offset, len), ref);
- }
- array2.close();
- }
- public void testByteArrayBulkSet() {
- final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
- getRandom().nextBytes(array1);
- final ByteArray array2 = bigArrays.newByteArray(array1.length, randomBoolean());
- for (int i = 0; i < array1.length; ) {
- final int len = Math.min(array1.length - i, randomBoolean() ? randomInt(10) : randomInt(3 * BigArrays.BYTE_PAGE_SIZE));
- array2.set(i, array1, i, len);
- i += len;
- }
- for (int i = 0; i < array1.length; ++i) {
- assertEquals(array1[i], array2.get(i));
- }
- array2.close();
- }
- public void testByteArrayEquals() {
- final ByteArray empty1 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
- final ByteArray empty2 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
- // identity = equality
- assertTrue(bigArrays.equals(empty1, empty1));
- // equality: both empty
- assertTrue(bigArrays.equals(empty1, empty2));
- empty1.close();
- empty2.close();
- // not equal: contents differ
- final ByteArray a1 = byteArrayWithBytes(new byte[]{0});
- final ByteArray a2 = byteArrayWithBytes(new byte[]{1});
- assertFalse(bigArrays.equals(a1, a2));
- a1.close();
- a2.close();
- // not equal: contents differ
- final ByteArray a3 = byteArrayWithBytes(new byte[]{1,2,3});
- final ByteArray a4 = byteArrayWithBytes(new byte[]{1, 1, 3});
- assertFalse(bigArrays.equals(a3, a4));
- a3.close();
- a4.close();
- // not equal: contents differ
- final ByteArray a5 = byteArrayWithBytes(new byte[]{1,2,3});
- final ByteArray a6 = byteArrayWithBytes(new byte[]{1,2,4});
- assertFalse(bigArrays.equals(a5, a6));
- a5.close();
- a6.close();
- }
- public void testByteArrayHashCode() {
- // null arg has hashCode 0
- assertEquals(0, bigArrays.hashCode(null));
- // empty array should have equal hash
- final int emptyHash = Arrays.hashCode(BytesRef.EMPTY_BYTES);
- final ByteArray emptyByteArray = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
- final int emptyByteArrayHash = bigArrays.hashCode(emptyByteArray);
- assertEquals(emptyHash, emptyByteArrayHash);
- emptyByteArray.close();
- // FUN FACT: Arrays.hashCode() and BytesReference.bytesHashCode() are inconsistent for empty byte[]
- // final int emptyHash3 = new BytesArray(BytesRef.EMPTY_BYTES).hashCode();
- // assertEquals(emptyHash1, emptyHash3); -> fail (1 vs. 0)
- // large arrays should be different
- final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
- getRandom().nextBytes(array1);
- final int array1Hash = Arrays.hashCode(array1);
- final ByteArray array2 = byteArrayWithBytes(array1);
- final int array2Hash = bigArrays.hashCode(array2);
- assertEquals(array1Hash, array2Hash);
- array2.close();
- }
- private ByteArray byteArrayWithBytes(byte[] bytes) {
- ByteArray bytearray = bigArrays.newByteArray(bytes.length);
- for (int i = 0; i < bytes.length; ++i) {
- bytearray.set(i, bytes[i]);
- }
- return bytearray;
- }
- public void testMaxSizeExceededOnNew() throws Exception {
- final int size = scaledRandomIntBetween(5, 1 << 22);
- for (String type : Arrays.asList("Byte", "Int", "Long", "Float", "Double", "Object")) {
- HierarchyCircuitBreakerService hcbs = new HierarchyCircuitBreakerService(
- ImmutableSettings.builder()
- .put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, size)
- .build(),
- new NodeSettingsService(ImmutableSettings.EMPTY));
- BigArrays bigArrays = new BigArrays(ImmutableSettings.EMPTY, null, hcbs).withCircuitBreaking();
- Method create = BigArrays.class.getMethod("new" + type + "Array", long.class);
- try {
- create.invoke(bigArrays, size);
- fail("expected an exception on " + create);
- } catch (InvocationTargetException e) {
- assertTrue(e.getCause() instanceof CircuitBreakingException);
- }
- assertEquals(0, hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
- }
- }
- public void testMaxSizeExceededOnResize() throws Exception {
- for (String type : Arrays.asList("Byte", "Int", "Long", "Float", "Double", "Object")) {
- final long maxSize = randomIntBetween(1 << 10, 1 << 22);
- HierarchyCircuitBreakerService hcbs = new HierarchyCircuitBreakerService(
- ImmutableSettings.builder()
- .put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, maxSize)
- .build(),
- new NodeSettingsService(ImmutableSettings.EMPTY));
- BigArrays bigArrays = new BigArrays(ImmutableSettings.EMPTY, null, hcbs).withCircuitBreaking();
- Method create = BigArrays.class.getMethod("new" + type + "Array", long.class);
- final int size = scaledRandomIntBetween(1, 20);
- BigArray array = (BigArray) create.invoke(bigArrays, size);
- Method resize = BigArrays.class.getMethod("resize", array.getClass().getInterfaces()[0], long.class);
- while (true) {
- long newSize = array.size() * 2;
- try {
- array = (BigArray) resize.invoke(bigArrays, array, newSize);
- } catch (InvocationTargetException e) {
- assertTrue(e.getCause() instanceof CircuitBreakingException);
- break;
- }
- }
- assertEquals(array.ramBytesUsed(), hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
- array.close();
- assertEquals(0, hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
- }
- }
- }
|