001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.nio.ByteBuffer; 027import java.util.Random; 028 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.nio.ByteBuff; 031import org.apache.hadoop.hbase.nio.MultiByteBuff; 032import org.apache.hadoop.hbase.nio.SingleByteBuff; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.hbase.testclassification.SmallTests; 035import org.junit.ClassRule; 036import org.junit.Test; 037import org.junit.experimental.categories.Category; 038 039@Category({ MiscTests.class, SmallTests.class }) 040public class TestByteBufferArray { 041 042 private static final Random RANDOM = new Random(System.currentTimeMillis()); 043 044 @ClassRule 045 public static final HBaseClassTestRule CLASS_RULE = 046 HBaseClassTestRule.forClass(TestByteBufferArray.class); 047 048 private static final ByteBufferAllocator ALLOC = (size) -> ByteBuffer.allocateDirect((int) size); 049 050 @Test 051 public void testAsSubBufferWhenEndOffsetLandInLastBuffer() throws Exception { 052 int capacity = 4 * 1024 * 1024; 053 ByteBufferArray array = new ByteBufferArray(capacity, ALLOC); 054 ByteBuff subBuf = ByteBuff.wrap(array.asSubByteBuffers(0, capacity)); 055 subBuf.position(capacity - 1);// Position to the last byte 056 assertTrue(subBuf.hasRemaining()); 057 // Read last byte 058 subBuf.get(); 059 assertFalse(subBuf.hasRemaining()); 060 } 061 062 @Test 063 public void testByteBufferCreation() throws Exception { 064 int capacity = 470 * 1021 * 1023; 065 ByteBufferArray array = new ByteBufferArray(capacity, ALLOC); 066 assertEquals(118, array.buffers.length); 067 for (int i = 0; i < array.buffers.length; i++) { 068 assertEquals(ByteBufferArray.DEFAULT_BUFFER_SIZE, array.buffers[i].capacity()); 069 } 070 } 071 072 @Test 073 public void testByteBufferCreation1() throws Exception { 074 long cap = 7 * 1024L * 1024L; 075 int bufferSize = ByteBufferArray.getBufferSize(cap), bufferCount = 25; 076 ByteBufferArray array = new ByteBufferArray(bufferSize, bufferCount, 16, cap, ALLOC); 077 for (int i = 0; i < array.buffers.length; i++) { 078 assertEquals(458752, array.buffers[i].capacity()); 079 } 080 } 081 082 private static void fill(ByteBuff buf, byte val) { 083 for (int i = buf.position(); i < buf.limit(); i++) { 084 buf.put(i, val); 085 } 086 } 087 088 private ByteBuff createByteBuff(int len) { 089 assert len >= 0; 090 int pos = len == 0 ? 0 : RANDOM.nextInt(len); 091 ByteBuff b = ByteBuff.wrap(ByteBuffer.allocate(2 * len)); 092 b.position(pos).limit(pos + len); 093 return b; 094 } 095 096 private interface Call { 097 void run() throws IOException; 098 } 099 100 @SuppressWarnings("TryFailThrowable") 101 private void expectedAssert(Call r) throws IOException { 102 try { 103 r.run(); 104 fail(); 105 } catch (AssertionError e) { 106 // Ignore 107 } 108 } 109 110 111 @Test 112 public void testArrayIO() throws IOException { 113 int cap = 9 * 1024 * 1024, bufferSize = ByteBufferArray.getBufferSize(cap); 114 ByteBufferArray array = new ByteBufferArray(cap, ALLOC); 115 testReadAndWrite(array, 0, 512, (byte) 2); 116 testReadAndWrite(array, cap - 512, 512, (byte) 3); 117 testReadAndWrite(array, 4 * 1024 * 1024, 5 * 1024 * 1024, (byte) 4); 118 testReadAndWrite(array, 256, 256, (byte) 5); 119 testReadAndWrite(array, 257, 513, (byte) 6); 120 testReadAndWrite(array, 0, cap, (byte) 7); 121 testReadAndWrite(array, cap, 0, (byte) 8); 122 testReadAndWrite(array, cap - 1, 1, (byte) 9); 123 testReadAndWrite(array, cap - 2, 2, (byte) 10); 124 125 expectedAssert(() -> testReadAndWrite(array, cap - 2, 3, (byte) 11)); 126 expectedAssert(() -> testReadAndWrite(array, cap + 1, 0, (byte) 12)); 127 expectedAssert(() -> testReadAndWrite(array, 0, cap + 1, (byte) 12)); 128 expectedAssert(() -> testReadAndWrite(array, -1, 0, (byte) 13)); 129 expectedAssert(() -> testReadAndWrite(array, 0, -23, (byte) 14)); 130 expectedAssert(() -> testReadAndWrite(array, 0, 0, (byte) 15)); 131 expectedAssert(() -> testReadAndWrite(array, 4096, cap - 4096 + 1, (byte) 16)); 132 133 testAsSubByteBuff(array, 0, cap, true); 134 testAsSubByteBuff(array, 0, 0, false); 135 testAsSubByteBuff(array, 0, 1, false); 136 testAsSubByteBuff(array, 0, bufferSize - 1, false); 137 testAsSubByteBuff(array, 0, bufferSize, false); 138 testAsSubByteBuff(array, 0, bufferSize + 1, true); 139 testAsSubByteBuff(array, 0, 2 * bufferSize, true); 140 testAsSubByteBuff(array, 0, 5 * bufferSize, true); 141 testAsSubByteBuff(array, cap - bufferSize - 1, bufferSize, true); 142 testAsSubByteBuff(array, cap - bufferSize, bufferSize, false); 143 testAsSubByteBuff(array, cap - bufferSize, 0, false); 144 testAsSubByteBuff(array, cap - bufferSize, 1, false); 145 testAsSubByteBuff(array, cap - bufferSize, bufferSize - 1, false); 146 testAsSubByteBuff(array, cap - 2 * bufferSize, 2 * bufferSize, true); 147 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize + 1, true); 148 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize - 1, false); 149 testAsSubByteBuff(array, cap - 2 * bufferSize, 0, false); 150 151 expectedAssert(() -> testAsSubByteBuff(array, 0, cap + 1, false)); 152 expectedAssert(() -> testAsSubByteBuff(array, 0, -1, false)); 153 expectedAssert(() -> testAsSubByteBuff(array, -1, -1, false)); 154 expectedAssert(() -> testAsSubByteBuff(array, cap - bufferSize, bufferSize + 1, false)); 155 expectedAssert(() -> testAsSubByteBuff(array, 2 * bufferSize, cap - 2 * bufferSize + 1, false)); 156 } 157 158 private void testReadAndWrite(ByteBufferArray array, int off, int dataSize, byte val) { 159 ByteBuff src = createByteBuff(dataSize); 160 int pos = src.position(), lim = src.limit(); 161 fill(src, val); 162 assertEquals(src.remaining(), dataSize); 163 try { 164 assertEquals(dataSize, array.write(off, src)); 165 assertEquals(0, src.remaining()); 166 } finally { 167 src.position(pos).limit(lim); 168 } 169 170 ByteBuff dst = createByteBuff(dataSize); 171 pos = dst.position(); 172 lim = dst.limit(); 173 try { 174 assertEquals(dataSize, array.read(off, dst)); 175 assertEquals(0, dst.remaining()); 176 } finally { 177 dst.position(pos).limit(lim); 178 } 179 assertByteBuffEquals(src, dst); 180 } 181 182 private void testAsSubByteBuff(ByteBufferArray array, int off, int len, boolean isMulti) { 183 ByteBuff ret = ByteBuff.wrap(array.asSubByteBuffers(off, len)); 184 if (isMulti) { 185 assertTrue(ret instanceof MultiByteBuff); 186 } else { 187 assertTrue(ret instanceof SingleByteBuff); 188 } 189 assertTrue(!ret.hasArray()); 190 assertEquals(len, ret.remaining()); 191 192 ByteBuff tmp = createByteBuff(len); 193 int pos = tmp.position(), lim = tmp.limit(); 194 try { 195 assertEquals(len, array.read(off, tmp)); 196 assertEquals(0, tmp.remaining()); 197 } finally { 198 tmp.position(pos).limit(lim); 199 } 200 201 assertByteBuffEquals(ret, tmp); 202 } 203 204 private void assertByteBuffEquals(ByteBuff a, ByteBuff b) { 205 assertEquals(a.remaining(), b.remaining()); 206 for (int i = a.position(), j = b.position(); i < a.limit(); i++, j++) { 207 assertEquals(a.get(i), b.get(j)); 208 } 209 } 210}