BigArraysTests.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Licensed to Elasticsearch under one or more contributor
  3. * license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright
  5. * ownership. Elasticsearch licenses this file to you under
  6. * the Apache License, Version 2.0 (the "License"); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.elasticsearch.common.util;
  20. import org.apache.lucene.util.BytesRef;
  21. import org.elasticsearch.cache.recycler.PageCacheRecycler;
  22. import org.elasticsearch.common.breaker.CircuitBreaker;
  23. import org.elasticsearch.common.breaker.CircuitBreakingException;
  24. import org.elasticsearch.common.settings.ImmutableSettings;
  25. import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
  26. import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
  27. import org.elasticsearch.node.settings.NodeSettingsService;
  28. import org.elasticsearch.test.ElasticsearchTestCase;
  29. import org.elasticsearch.test.cache.recycler.MockBigArrays;
  30. import org.elasticsearch.test.cache.recycler.MockPageCacheRecycler;
  31. import org.elasticsearch.threadpool.ThreadPool;
  32. import org.junit.Before;
  33. import java.lang.reflect.InvocationTargetException;
  34. import java.lang.reflect.Method;
  35. import java.util.Arrays;
  36. public class BigArraysTests extends ElasticsearchTestCase {
  37. public static BigArrays randombigArrays() {
  38. final PageCacheRecycler recycler = randomBoolean() ? null : new MockPageCacheRecycler(ImmutableSettings.EMPTY, new ThreadPool("BigArraysTests"));
  39. return new MockBigArrays(ImmutableSettings.EMPTY, recycler, new NoneCircuitBreakerService());
  40. }
  41. private BigArrays bigArrays;
  42. @Before
  43. public void init() {
  44. bigArrays = randombigArrays();
  45. }
  46. public void testByteArrayGrowth() {
  47. final int totalLen = randomIntBetween(1, 4000000);
  48. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  49. ByteArray array = bigArrays.newByteArray(startLen, randomBoolean());
  50. byte[] ref = new byte[totalLen];
  51. for (int i = 0; i < totalLen; ++i) {
  52. ref[i] = randomByte();
  53. array = bigArrays.grow(array, i + 1);
  54. array.set(i, ref[i]);
  55. }
  56. for (int i = 0; i < totalLen; ++i) {
  57. assertEquals(ref[i], array.get(i));
  58. }
  59. array.close();
  60. }
  61. public void testIntArrayGrowth() {
  62. final int totalLen = randomIntBetween(1, 1000000);
  63. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  64. IntArray array = bigArrays.newIntArray(startLen, randomBoolean());
  65. int[] ref = new int[totalLen];
  66. for (int i = 0; i < totalLen; ++i) {
  67. ref[i] = randomInt();
  68. array = bigArrays.grow(array, i + 1);
  69. array.set(i, ref[i]);
  70. }
  71. for (int i = 0; i < totalLen; ++i) {
  72. assertEquals(ref[i], array.get(i));
  73. }
  74. array.close();
  75. }
  76. public void testLongArrayGrowth() {
  77. final int totalLen = randomIntBetween(1, 1000000);
  78. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  79. LongArray array = bigArrays.newLongArray(startLen, randomBoolean());
  80. long[] ref = new long[totalLen];
  81. for (int i = 0; i < totalLen; ++i) {
  82. ref[i] = randomLong();
  83. array = bigArrays.grow(array, i + 1);
  84. array.set(i, ref[i]);
  85. }
  86. for (int i = 0; i < totalLen; ++i) {
  87. assertEquals(ref[i], array.get(i));
  88. }
  89. array.close();
  90. }
  91. public void testFloatArrayGrowth() {
  92. final int totalLen = randomIntBetween(1, 1000000);
  93. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  94. FloatArray array = bigArrays.newFloatArray(startLen, randomBoolean());
  95. float[] ref = new float[totalLen];
  96. for (int i = 0; i < totalLen; ++i) {
  97. ref[i] = randomFloat();
  98. array = bigArrays.grow(array, i + 1);
  99. array.set(i, ref[i]);
  100. }
  101. for (int i = 0; i < totalLen; ++i) {
  102. assertEquals(ref[i], array.get(i), 0.001d);
  103. }
  104. array.close();
  105. }
  106. public void testDoubleArrayGrowth() {
  107. final int totalLen = randomIntBetween(1, 1000000);
  108. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  109. DoubleArray array = bigArrays.newDoubleArray(startLen, randomBoolean());
  110. double[] ref = new double[totalLen];
  111. for (int i = 0; i < totalLen; ++i) {
  112. ref[i] = randomDouble();
  113. array = bigArrays.grow(array, i + 1);
  114. array.set(i, ref[i]);
  115. }
  116. for (int i = 0; i < totalLen; ++i) {
  117. assertEquals(ref[i], array.get(i), 0.001d);
  118. }
  119. array.close();
  120. }
  121. public void testObjectArrayGrowth() {
  122. final int totalLen = randomIntBetween(1, 1000000);
  123. final int startLen = randomIntBetween(1, randomBoolean() ? 1000 : totalLen);
  124. ObjectArray<Object> array = bigArrays.newObjectArray(startLen);
  125. final Object[] pool = new Object[100];
  126. for (int i = 0; i < pool.length; ++i) {
  127. pool[i] = new Object();
  128. }
  129. Object[] ref = new Object[totalLen];
  130. for (int i = 0; i < totalLen; ++i) {
  131. ref[i] = randomFrom(pool);
  132. array = bigArrays.grow(array, i + 1);
  133. array.set(i, ref[i]);
  134. }
  135. for (int i = 0; i < totalLen; ++i) {
  136. assertSame(ref[i], array.get(i));
  137. }
  138. array.close();
  139. }
  140. public void testByteArrayFill() {
  141. final int len = randomIntBetween(1, 100000);
  142. final int fromIndex = randomIntBetween(0, len - 1);
  143. final int toIndex = randomBoolean()
  144. ? Math.min(fromIndex + randomInt(100), len) // single page
  145. : randomIntBetween(fromIndex, len); // likely multiple pages
  146. final ByteArray array2 = bigArrays.newByteArray(len, randomBoolean());
  147. final byte[] array1 = new byte[len];
  148. for (int i = 0; i < len; ++i) {
  149. array1[i] = randomByte();
  150. array2.set(i, array1[i]);
  151. }
  152. final byte rand = randomByte();
  153. Arrays.fill(array1, fromIndex, toIndex, rand);
  154. array2.fill(fromIndex, toIndex, rand);
  155. for (int i = 0; i < len; ++i) {
  156. assertEquals(array1[i], array2.get(i), 0.001d);
  157. }
  158. array2.close();
  159. }
  160. public void testFloatArrayFill() {
  161. final int len = randomIntBetween(1, 100000);
  162. final int fromIndex = randomIntBetween(0, len - 1);
  163. final int toIndex = randomBoolean()
  164. ? Math.min(fromIndex + randomInt(100), len) // single page
  165. : randomIntBetween(fromIndex, len); // likely multiple pages
  166. final FloatArray array2 = bigArrays.newFloatArray(len, randomBoolean());
  167. final float[] array1 = new float[len];
  168. for (int i = 0; i < len; ++i) {
  169. array1[i] = randomFloat();
  170. array2.set(i, array1[i]);
  171. }
  172. final float rand = randomFloat();
  173. Arrays.fill(array1, fromIndex, toIndex, rand);
  174. array2.fill(fromIndex, toIndex, rand);
  175. for (int i = 0; i < len; ++i) {
  176. assertEquals(array1[i], array2.get(i), 0.001d);
  177. }
  178. array2.close();
  179. }
  180. public void testDoubleArrayFill() {
  181. final int len = randomIntBetween(1, 100000);
  182. final int fromIndex = randomIntBetween(0, len - 1);
  183. final int toIndex = randomBoolean()
  184. ? Math.min(fromIndex + randomInt(100), len) // single page
  185. : randomIntBetween(fromIndex, len); // likely multiple pages
  186. final DoubleArray array2 = bigArrays.newDoubleArray(len, randomBoolean());
  187. final double[] array1 = new double[len];
  188. for (int i = 0; i < len; ++i) {
  189. array1[i] = randomDouble();
  190. array2.set(i, array1[i]);
  191. }
  192. final double rand = randomDouble();
  193. Arrays.fill(array1, fromIndex, toIndex, rand);
  194. array2.fill(fromIndex, toIndex, rand);
  195. for (int i = 0; i < len; ++i) {
  196. assertEquals(array1[i], array2.get(i), 0.001d);
  197. }
  198. array2.close();
  199. }
  200. public void testLongArrayFill() {
  201. final int len = randomIntBetween(1, 100000);
  202. final int fromIndex = randomIntBetween(0, len - 1);
  203. final int toIndex = randomBoolean()
  204. ? Math.min(fromIndex + randomInt(100), len) // single page
  205. : randomIntBetween(fromIndex, len); // likely multiple pages
  206. final LongArray array2 = bigArrays.newLongArray(len, randomBoolean());
  207. final long[] array1 = new long[len];
  208. for (int i = 0; i < len; ++i) {
  209. array1[i] = randomLong();
  210. array2.set(i, array1[i]);
  211. }
  212. final long rand = randomLong();
  213. Arrays.fill(array1, fromIndex, toIndex, rand);
  214. array2.fill(fromIndex, toIndex, rand);
  215. for (int i = 0; i < len; ++i) {
  216. assertEquals(array1[i], array2.get(i));
  217. }
  218. array2.close();
  219. }
  220. public void testByteArrayBulkGet() {
  221. final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
  222. getRandom().nextBytes(array1);
  223. final ByteArray array2 = bigArrays.newByteArray(array1.length, randomBoolean());
  224. for (int i = 0; i < array1.length; ++i) {
  225. array2.set(i, array1[i]);
  226. }
  227. final BytesRef ref = new BytesRef();
  228. for (int i = 0; i < 1000; ++i) {
  229. final int offset = randomInt(array1.length - 1);
  230. final int len = randomInt(Math.min(randomBoolean() ? 10 : Integer.MAX_VALUE, array1.length - offset));
  231. array2.get(offset, len, ref);
  232. assertEquals(new BytesRef(array1, offset, len), ref);
  233. }
  234. array2.close();
  235. }
  236. public void testByteArrayBulkSet() {
  237. final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
  238. getRandom().nextBytes(array1);
  239. final ByteArray array2 = bigArrays.newByteArray(array1.length, randomBoolean());
  240. for (int i = 0; i < array1.length; ) {
  241. final int len = Math.min(array1.length - i, randomBoolean() ? randomInt(10) : randomInt(3 * BigArrays.BYTE_PAGE_SIZE));
  242. array2.set(i, array1, i, len);
  243. i += len;
  244. }
  245. for (int i = 0; i < array1.length; ++i) {
  246. assertEquals(array1[i], array2.get(i));
  247. }
  248. array2.close();
  249. }
  250. public void testByteArrayEquals() {
  251. final ByteArray empty1 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
  252. final ByteArray empty2 = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
  253. // identity = equality
  254. assertTrue(bigArrays.equals(empty1, empty1));
  255. // equality: both empty
  256. assertTrue(bigArrays.equals(empty1, empty2));
  257. empty1.close();
  258. empty2.close();
  259. // not equal: contents differ
  260. final ByteArray a1 = byteArrayWithBytes(new byte[]{0});
  261. final ByteArray a2 = byteArrayWithBytes(new byte[]{1});
  262. assertFalse(bigArrays.equals(a1, a2));
  263. a1.close();
  264. a2.close();
  265. // not equal: contents differ
  266. final ByteArray a3 = byteArrayWithBytes(new byte[]{1,2,3});
  267. final ByteArray a4 = byteArrayWithBytes(new byte[]{1, 1, 3});
  268. assertFalse(bigArrays.equals(a3, a4));
  269. a3.close();
  270. a4.close();
  271. // not equal: contents differ
  272. final ByteArray a5 = byteArrayWithBytes(new byte[]{1,2,3});
  273. final ByteArray a6 = byteArrayWithBytes(new byte[]{1,2,4});
  274. assertFalse(bigArrays.equals(a5, a6));
  275. a5.close();
  276. a6.close();
  277. }
  278. public void testByteArrayHashCode() {
  279. // null arg has hashCode 0
  280. assertEquals(0, bigArrays.hashCode(null));
  281. // empty array should have equal hash
  282. final int emptyHash = Arrays.hashCode(BytesRef.EMPTY_BYTES);
  283. final ByteArray emptyByteArray = byteArrayWithBytes(BytesRef.EMPTY_BYTES);
  284. final int emptyByteArrayHash = bigArrays.hashCode(emptyByteArray);
  285. assertEquals(emptyHash, emptyByteArrayHash);
  286. emptyByteArray.close();
  287. // FUN FACT: Arrays.hashCode() and BytesReference.bytesHashCode() are inconsistent for empty byte[]
  288. // final int emptyHash3 = new BytesArray(BytesRef.EMPTY_BYTES).hashCode();
  289. // assertEquals(emptyHash1, emptyHash3); -> fail (1 vs. 0)
  290. // large arrays should be different
  291. final byte[] array1 = new byte[randomIntBetween(1, 4000000)];
  292. getRandom().nextBytes(array1);
  293. final int array1Hash = Arrays.hashCode(array1);
  294. final ByteArray array2 = byteArrayWithBytes(array1);
  295. final int array2Hash = bigArrays.hashCode(array2);
  296. assertEquals(array1Hash, array2Hash);
  297. array2.close();
  298. }
  299. private ByteArray byteArrayWithBytes(byte[] bytes) {
  300. ByteArray bytearray = bigArrays.newByteArray(bytes.length);
  301. for (int i = 0; i < bytes.length; ++i) {
  302. bytearray.set(i, bytes[i]);
  303. }
  304. return bytearray;
  305. }
  306. public void testMaxSizeExceededOnNew() throws Exception {
  307. final int size = scaledRandomIntBetween(5, 1 << 22);
  308. for (String type : Arrays.asList("Byte", "Int", "Long", "Float", "Double", "Object")) {
  309. HierarchyCircuitBreakerService hcbs = new HierarchyCircuitBreakerService(
  310. ImmutableSettings.builder()
  311. .put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, size)
  312. .build(),
  313. new NodeSettingsService(ImmutableSettings.EMPTY));
  314. BigArrays bigArrays = new BigArrays(ImmutableSettings.EMPTY, null, hcbs).withCircuitBreaking();
  315. Method create = BigArrays.class.getMethod("new" + type + "Array", long.class);
  316. try {
  317. create.invoke(bigArrays, size);
  318. fail("expected an exception on " + create);
  319. } catch (InvocationTargetException e) {
  320. assertTrue(e.getCause() instanceof CircuitBreakingException);
  321. }
  322. assertEquals(0, hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
  323. }
  324. }
  325. public void testMaxSizeExceededOnResize() throws Exception {
  326. for (String type : Arrays.asList("Byte", "Int", "Long", "Float", "Double", "Object")) {
  327. final long maxSize = randomIntBetween(1 << 10, 1 << 22);
  328. HierarchyCircuitBreakerService hcbs = new HierarchyCircuitBreakerService(
  329. ImmutableSettings.builder()
  330. .put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, maxSize)
  331. .build(),
  332. new NodeSettingsService(ImmutableSettings.EMPTY));
  333. BigArrays bigArrays = new BigArrays(ImmutableSettings.EMPTY, null, hcbs).withCircuitBreaking();
  334. Method create = BigArrays.class.getMethod("new" + type + "Array", long.class);
  335. final int size = scaledRandomIntBetween(1, 20);
  336. BigArray array = (BigArray) create.invoke(bigArrays, size);
  337. Method resize = BigArrays.class.getMethod("resize", array.getClass().getInterfaces()[0], long.class);
  338. while (true) {
  339. long newSize = array.size() * 2;
  340. try {
  341. array = (BigArray) resize.invoke(bigArrays, array, newSize);
  342. } catch (InvocationTargetException e) {
  343. assertTrue(e.getCause() instanceof CircuitBreakingException);
  344. break;
  345. }
  346. }
  347. assertEquals(array.ramBytesUsed(), hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
  348. array.close();
  349. assertEquals(0, hcbs.getBreaker(CircuitBreaker.Name.REQUEST).getUsed());
  350. }
  351. }
  352. }