PagedBytesReferenceTest.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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.bytes;
  20. import org.apache.lucene.util.BytesRef;
  21. import org.elasticsearch.common.io.stream.BytesStreamOutput;
  22. import org.elasticsearch.common.io.stream.StreamInput;
  23. import org.elasticsearch.common.settings.ImmutableSettings;
  24. import org.elasticsearch.common.util.BigArrays;
  25. import org.elasticsearch.common.util.ByteArray;
  26. import org.elasticsearch.test.ElasticsearchTestCase;
  27. import org.elasticsearch.test.cache.recycler.MockBigArrays;
  28. import org.jboss.netty.buffer.ChannelBuffer;
  29. import org.junit.After;
  30. import org.junit.Before;
  31. import org.junit.Test;
  32. import java.io.EOFException;
  33. import java.io.IOException;
  34. import java.util.Arrays;
  35. public class PagedBytesReferenceTest extends ElasticsearchTestCase {
  36. private static final int PAGE_SIZE = BigArrays.BYTE_PAGE_SIZE;
  37. private MockBigArrays bigarrays;
  38. @Before
  39. public void setUp() throws Exception {
  40. super.setUp();
  41. bigarrays = new MockBigArrays(ImmutableSettings.EMPTY, null);
  42. }
  43. @After
  44. public void tearDown() throws Exception {
  45. // necessary since we currently never release BigArrays
  46. MockBigArrays.reset();
  47. super.tearDown();
  48. }
  49. @Test
  50. public void testGet() {
  51. int length = randomIntBetween(1, PAGE_SIZE * 3);
  52. BytesReference pbr = getRandomizedPagedBytesReference(length);
  53. int sliceOffset = randomIntBetween(0, length / 2);
  54. int sliceLength = Math.max(1, length - sliceOffset - 1);
  55. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  56. assertEquals(pbr.get(sliceOffset), slice.get(0));
  57. assertEquals(pbr.get(sliceOffset + sliceLength), slice.get(sliceLength));
  58. }
  59. public void testLength() {
  60. int[] sizes = {0, randomInt(PAGE_SIZE), PAGE_SIZE, randomInt(PAGE_SIZE * 3)};
  61. for (int i = 0; i < sizes.length; i++) {
  62. BytesReference pbr = getRandomizedPagedBytesReference(sizes[i]);
  63. assertEquals(sizes[i], pbr.length());
  64. }
  65. }
  66. public void testSlice() {
  67. int length = randomInt(PAGE_SIZE * 3);
  68. BytesReference pbr = getRandomizedPagedBytesReference(length);
  69. int sliceOffset = randomIntBetween(0, length / 2);
  70. int sliceLength = Math.max(0, length - sliceOffset - 1);
  71. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  72. assertEquals(sliceLength, slice.length());
  73. if (slice.hasArray()) {
  74. assertEquals(sliceOffset, slice.arrayOffset());
  75. }
  76. else {
  77. try {
  78. slice.arrayOffset();
  79. fail("expected IllegalStateException");
  80. }
  81. catch (IllegalStateException ise) {
  82. // expected
  83. }
  84. }
  85. }
  86. public void testStreamInput() throws IOException {
  87. int length = randomIntBetween(10, PAGE_SIZE * 3);
  88. BytesReference pbr = getRandomizedPagedBytesReference(length);
  89. StreamInput si = pbr.streamInput();
  90. assertNotNull(si);
  91. // read single bytes one by one
  92. assertEquals(pbr.get(0), si.readByte());
  93. assertEquals(pbr.get(1), si.readByte());
  94. assertEquals(pbr.get(2), si.readByte());
  95. si.reset();
  96. // buffer for bulk reads
  97. byte[] origBuf = new byte[length];
  98. getRandom().nextBytes(origBuf);
  99. byte[] targetBuf = Arrays.copyOf(origBuf, origBuf.length);
  100. // bulk-read 0 bytes: must not modify buffer
  101. si.readBytes(targetBuf, 0, 0);
  102. assertEquals(origBuf[0], targetBuf[0]);
  103. si.reset();
  104. // read a few few bytes as ints
  105. int bytesToRead = randomIntBetween(1, length/2);
  106. for (int i = 0; i < bytesToRead; i++) {
  107. int b = si.read();
  108. assertEquals(pbr.get(i), b);
  109. }
  110. si.reset();
  111. // bulk-read all
  112. si.readFully(targetBuf);
  113. assertArrayEquals(pbr.toBytes(), targetBuf);
  114. // continuing to read should now fail with EOFException
  115. try {
  116. si.readByte();
  117. fail("expected EOF");
  118. }
  119. catch (EOFException eof) {
  120. // yay
  121. }
  122. // try to read more than the stream contains
  123. si.reset();
  124. try {
  125. si.readBytes(targetBuf, 0, length * 2);
  126. fail("expected IndexOutOfBoundsException: le > stream.length");
  127. }
  128. catch (IndexOutOfBoundsException ioob) {
  129. // expected
  130. }
  131. }
  132. public void testSliceStreamInput() throws IOException {
  133. int length = randomIntBetween(10, PAGE_SIZE * 3);
  134. BytesReference pbr = getRandomizedPagedBytesReference(length);
  135. StreamInput si = pbr.streamInput();
  136. // test stream input over slice (upper half of original)
  137. int sliceOffset = randomIntBetween(1, length / 2);
  138. int sliceLength = length - sliceOffset;
  139. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  140. StreamInput sliceInput = slice.streamInput();
  141. // single reads
  142. assertEquals(slice.get(0), sliceInput.readByte());
  143. assertEquals(slice.get(1), sliceInput.readByte());
  144. assertEquals(slice.get(2), sliceInput.readByte());
  145. si.reset();
  146. // bulk read
  147. byte[] sliceBytes = new byte[sliceLength];
  148. sliceInput.readFully(sliceBytes);
  149. // compare slice content with upper half of original
  150. byte[] pbrSliceBytes = Arrays.copyOfRange(pbr.toBytes(), sliceOffset, length);
  151. assertArrayEquals(pbrSliceBytes, sliceBytes);
  152. // compare slice bytes with bytes read from slice via streamInput :D
  153. byte[] sliceToBytes = slice.toBytes();
  154. assertEquals(sliceBytes.length, sliceToBytes.length);
  155. assertArrayEquals(sliceBytes, sliceToBytes);
  156. }
  157. public void testWriteTo() throws IOException {
  158. int length = randomIntBetween(10, PAGE_SIZE * 4);
  159. BytesReference pbr = getRandomizedPagedBytesReference(length);
  160. BytesStreamOutput out = new BytesStreamOutput();
  161. pbr.writeTo(out);
  162. assertEquals(pbr.length(), out.size());
  163. assertArrayEquals(pbr.toBytes(), out.bytes().toBytes());
  164. out.close();
  165. }
  166. public void testSliceWriteTo() throws IOException {
  167. int length = randomIntBetween(10, PAGE_SIZE * randomIntBetween(2,5));
  168. BytesReference pbr = getRandomizedPagedBytesReference(length);
  169. int sliceOffset = randomIntBetween(1, length / 2);
  170. int sliceLength = length - sliceOffset;
  171. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  172. BytesStreamOutput sliceOut = new BytesStreamOutput(sliceLength);
  173. slice.writeTo(sliceOut);
  174. assertEquals(slice.length(), sliceOut.size());
  175. assertArrayEquals(slice.toBytes(), sliceOut.bytes().toBytes());
  176. sliceOut.close();
  177. }
  178. public void testToBytes() {
  179. int[] sizes = {0, randomInt(PAGE_SIZE), PAGE_SIZE, randomIntBetween(2, PAGE_SIZE * randomIntBetween(2,5))};
  180. for (int i = 0; i < sizes.length; i++) {
  181. BytesReference pbr = getRandomizedPagedBytesReference(sizes[i]);
  182. byte[] bytes = pbr.toBytes();
  183. assertEquals(sizes[i], bytes.length);
  184. // verify that toBytes() is cheap for small payloads
  185. if (sizes[i] <= PAGE_SIZE) {
  186. assertSame(bytes, pbr.toBytes());
  187. }
  188. else {
  189. assertNotSame(bytes, pbr.toBytes());
  190. }
  191. }
  192. }
  193. public void testToBytesArraySharedPage() {
  194. int length = randomIntBetween(10, PAGE_SIZE);
  195. BytesReference pbr = getRandomizedPagedBytesReference(length);
  196. BytesArray ba = pbr.toBytesArray();
  197. BytesArray ba2 = pbr.toBytesArray();
  198. assertNotNull(ba);
  199. assertNotNull(ba2);
  200. assertEquals(pbr.length(), ba.length());
  201. assertEquals(ba.length(), ba2.length());
  202. // single-page optimization
  203. assertSame(ba.array(), ba2.array());
  204. }
  205. public void testToBytesArrayMaterializedPages() {
  206. // we need a length != (n * pagesize) to avoid page sharing at boundaries
  207. int length = 0;
  208. while ((length % PAGE_SIZE) == 0) {
  209. length = randomIntBetween(PAGE_SIZE, PAGE_SIZE * randomIntBetween(2,5));
  210. }
  211. BytesReference pbr = getRandomizedPagedBytesReference(length);
  212. BytesArray ba = pbr.toBytesArray();
  213. BytesArray ba2 = pbr.toBytesArray();
  214. assertNotNull(ba);
  215. assertNotNull(ba2);
  216. assertEquals(pbr.length(), ba.length());
  217. assertEquals(ba.length(), ba2.length());
  218. // ensure no single-page optimization
  219. assertNotSame(ba.array(), ba2.array());
  220. }
  221. public void testCopyBytesArray() {
  222. // small PBR which would normally share the first page
  223. int length = randomIntBetween(10, PAGE_SIZE);
  224. BytesReference pbr = getRandomizedPagedBytesReference(length);
  225. BytesArray ba = pbr.copyBytesArray();
  226. BytesArray ba2 = pbr.copyBytesArray();
  227. assertNotNull(ba);
  228. assertNotSame(ba, ba2);
  229. assertNotSame(ba.array(), ba2.array());
  230. }
  231. public void testSliceCopyBytesArray() {
  232. int length = randomIntBetween(10, PAGE_SIZE * randomIntBetween(2,8));
  233. BytesReference pbr = getRandomizedPagedBytesReference(length);
  234. int sliceOffset = randomIntBetween(0, pbr.length());
  235. int sliceLength = randomIntBetween(pbr.length() - sliceOffset, pbr.length() - sliceOffset);
  236. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  237. BytesArray ba1 = slice.copyBytesArray();
  238. BytesArray ba2 = slice.copyBytesArray();
  239. assertNotNull(ba1);
  240. assertNotNull(ba2);
  241. assertNotSame(ba1.array(), ba2.array());
  242. assertArrayEquals(slice.toBytes(), ba1.array());
  243. assertArrayEquals(slice.toBytes(), ba2.array());
  244. assertArrayEquals(ba1.array(), ba2.array());
  245. }
  246. public void testToChannelBuffer() {
  247. int length = randomIntBetween(10, PAGE_SIZE * randomIntBetween(2,8));
  248. BytesReference pbr = getRandomizedPagedBytesReference(length);
  249. ChannelBuffer cb = pbr.toChannelBuffer();
  250. assertNotNull(cb);
  251. byte[] bufferBytes = new byte[length];
  252. cb.getBytes(0, bufferBytes);
  253. assertArrayEquals(pbr.toBytes(), bufferBytes);
  254. }
  255. public void testEmptyToChannelBuffer() {
  256. BytesReference pbr = getRandomizedPagedBytesReference(0);
  257. ChannelBuffer cb = pbr.toChannelBuffer();
  258. assertNotNull(cb);
  259. assertEquals(0, pbr.length());
  260. assertEquals(0, cb.capacity());
  261. }
  262. public void testSliceToChannelBuffer() {
  263. int length = randomIntBetween(10, PAGE_SIZE * randomIntBetween(2,8));
  264. BytesReference pbr = getRandomizedPagedBytesReference(length);
  265. int sliceOffset = randomIntBetween(0, pbr.length());
  266. int sliceLength = randomIntBetween(pbr.length() - sliceOffset, pbr.length() - sliceOffset);
  267. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  268. ChannelBuffer cbSlice = slice.toChannelBuffer();
  269. assertNotNull(cbSlice);
  270. byte[] sliceBufferBytes = new byte[sliceLength];
  271. cbSlice.getBytes(0, sliceBufferBytes);
  272. assertArrayEquals(slice.toBytes(), sliceBufferBytes);
  273. }
  274. public void testHasArray() {
  275. int length = randomIntBetween(10, PAGE_SIZE * randomIntBetween(1,3));
  276. BytesReference pbr = getRandomizedPagedBytesReference(length);
  277. // must return true for <= pagesize
  278. assertEquals(length <= PAGE_SIZE, pbr.hasArray());
  279. }
  280. public void testArray() {
  281. int[] sizes = {0, randomInt(PAGE_SIZE), PAGE_SIZE, randomIntBetween(2, PAGE_SIZE * randomIntBetween(2,5))};
  282. for (int i = 0; i < sizes.length; i++) {
  283. BytesReference pbr = getRandomizedPagedBytesReference(sizes[i]);
  284. // verify that array() is cheap for small payloads
  285. if (sizes[i] <= PAGE_SIZE) {
  286. byte[] array = pbr.array();
  287. assertNotNull(array);
  288. assertEquals(sizes[i], array.length);
  289. assertSame(array, pbr.array());
  290. }
  291. else {
  292. try {
  293. pbr.array();
  294. fail("expected IllegalStateException");
  295. }
  296. catch (IllegalStateException isx) {
  297. // expected
  298. }
  299. }
  300. }
  301. }
  302. public void testArrayOffset() {
  303. int length = randomInt(PAGE_SIZE * randomIntBetween(2,5));
  304. BytesReference pbr = getRandomizedPagedBytesReference(length);
  305. if (pbr.hasArray()) {
  306. assertEquals(0, pbr.arrayOffset());
  307. }
  308. else {
  309. try {
  310. pbr.arrayOffset();
  311. fail("expected IllegalStateException");
  312. }
  313. catch (IllegalStateException ise) {
  314. // expected
  315. }
  316. }
  317. }
  318. public void testSliceArrayOffset() {
  319. int length = randomInt(PAGE_SIZE * randomIntBetween(2,5));
  320. BytesReference pbr = getRandomizedPagedBytesReference(length);
  321. int sliceOffset = randomIntBetween(0, pbr.length());
  322. int sliceLength = randomIntBetween(pbr.length() - sliceOffset, pbr.length() - sliceOffset);
  323. BytesReference slice = pbr.slice(sliceOffset, sliceLength);
  324. if (slice.hasArray()) {
  325. assertEquals(sliceOffset, slice.arrayOffset());
  326. }
  327. else {
  328. try {
  329. slice.arrayOffset();
  330. fail("expected IllegalStateException");
  331. }
  332. catch (IllegalStateException ise) {
  333. // expected
  334. }
  335. }
  336. }
  337. public void testToUtf8() throws IOException {
  338. // test empty
  339. BytesReference pbr = getRandomizedPagedBytesReference(0);
  340. assertEquals("", pbr.toUtf8());
  341. // TODO: good way to test?
  342. }
  343. public void testToBytesRef() {
  344. int length = randomIntBetween(0, PAGE_SIZE);
  345. BytesReference pbr = getRandomizedPagedBytesReference(length);
  346. BytesRef ref = pbr.toBytesRef();
  347. assertNotNull(ref);
  348. assertEquals(pbr.arrayOffset(), ref.offset);
  349. assertEquals(pbr.length(), ref.length);
  350. }
  351. public void testSliceToBytesRef() {
  352. int length = randomIntBetween(0, PAGE_SIZE);
  353. BytesReference pbr = getRandomizedPagedBytesReference(length);
  354. // get a BytesRef from a slice
  355. int sliceOffset = randomIntBetween(0, pbr.length());
  356. int sliceLength = randomIntBetween(pbr.length() - sliceOffset, pbr.length() - sliceOffset);
  357. BytesRef sliceRef = pbr.slice(sliceOffset, sliceLength).toBytesRef();
  358. // note that these are only true if we have <= than a page, otherwise offset/length are shifted
  359. assertEquals(sliceOffset, sliceRef.offset);
  360. assertEquals(sliceLength, sliceRef.length);
  361. }
  362. public void testCopyBytesRef() {
  363. int length = randomIntBetween(0, PAGE_SIZE * randomIntBetween(2,5));
  364. BytesReference pbr = getRandomizedPagedBytesReference(length);
  365. BytesRef ref = pbr.copyBytesRef();
  366. assertNotNull(ref);
  367. assertEquals(pbr.length(), ref.length);
  368. }
  369. public void testHashCode() {
  370. // empty content must have hash 1 (JDK compat)
  371. BytesReference pbr = getRandomizedPagedBytesReference(0);
  372. assertEquals(Arrays.hashCode(BytesRef.EMPTY_BYTES), pbr.hashCode());
  373. // test with content
  374. pbr = getRandomizedPagedBytesReference(randomIntBetween(0, PAGE_SIZE * randomIntBetween(2,5)));
  375. int jdkHash = Arrays.hashCode(pbr.toBytes());
  376. int pbrHash = pbr.hashCode();
  377. assertEquals(jdkHash, pbrHash);
  378. // test hashes of slices
  379. int sliceFrom = randomIntBetween(0, pbr.length());
  380. int sliceLength = randomIntBetween(pbr.length() - sliceFrom, pbr.length() - sliceFrom);
  381. BytesReference slice = pbr.slice(sliceFrom, sliceLength);
  382. int sliceJdkHash = Arrays.hashCode(slice.toBytes());
  383. int sliceHash = slice.hashCode();
  384. assertEquals(sliceJdkHash, sliceHash);
  385. }
  386. public void testEquals() {
  387. int length = randomIntBetween(100, PAGE_SIZE * randomIntBetween(2,5));
  388. ByteArray ba1 = bigarrays.newByteArray(length, false);
  389. ByteArray ba2 = bigarrays.newByteArray(length, false);
  390. // copy contents
  391. for (long i = 0; i < length; i++) {
  392. ba2.set(i, ba1.get(i));
  393. }
  394. // get refs & compare
  395. BytesReference pbr = new PagedBytesReference(bigarrays, ba1, length);
  396. BytesReference pbr2 = new PagedBytesReference(bigarrays, ba2, length);
  397. assertEquals(pbr, pbr2);
  398. }
  399. public void testEqualsPeerClass() {
  400. int length = randomIntBetween(100, PAGE_SIZE * randomIntBetween(2,5));
  401. BytesReference pbr = getRandomizedPagedBytesReference(length);
  402. BytesReference ba = new BytesArray(pbr.toBytes());
  403. assertEquals(pbr, ba);
  404. }
  405. public void testSliceEquals() {
  406. int length = randomIntBetween(100, PAGE_SIZE * randomIntBetween(2,5));
  407. ByteArray ba1 = bigarrays.newByteArray(length, false);
  408. BytesReference pbr = new PagedBytesReference(bigarrays, ba1, length);
  409. // test equality of slices
  410. int sliceFrom = randomIntBetween(0, pbr.length());
  411. int sliceLength = randomIntBetween(pbr.length() - sliceFrom, pbr.length() - sliceFrom);
  412. BytesReference slice1 = pbr.slice(sliceFrom, sliceLength);
  413. BytesReference slice2 = pbr.slice(sliceFrom, sliceLength);
  414. assertArrayEquals(slice1.toBytes(), slice2.toBytes());
  415. // test a slice with same offset but different length,
  416. // unless randomized testing gave us a 0-length slice.
  417. if (sliceLength > 0) {
  418. BytesReference slice3 = pbr.slice(sliceFrom, sliceLength / 2);
  419. assertFalse(Arrays.equals(slice1.toBytes(), slice3.toBytes()));
  420. }
  421. }
  422. private BytesReference getRandomizedPagedBytesReference(int length) {
  423. return new PagedBytesReference(bigarrays, bigarrays.newByteArray(length, false), length);
  424. }
  425. }