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.concurrent.ThreadLocalRandom; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.nio.ByteBuff; 030import org.apache.hadoop.hbase.nio.MultiByteBuff; 031import org.apache.hadoop.hbase.nio.SingleByteBuff; 032import org.apache.hadoop.hbase.testclassification.MiscTests; 033import org.apache.hadoop.hbase.testclassification.SmallTests; 034import org.junit.ClassRule; 035import org.junit.Test; 036import org.junit.experimental.categories.Category; 037 038@Category({ MiscTests.class, SmallTests.class }) 039public class TestByteBufferArray { 040 041 @ClassRule 042 public static final HBaseClassTestRule CLASS_RULE = 043 HBaseClassTestRule.forClass(TestByteBufferArray.class); 044 045 private static final ByteBufferAllocator ALLOC = (size) -> ByteBuffer.allocateDirect((int) size); 046 047 @Test 048 public void testAsSubBufferWhenEndOffsetLandInLastBuffer() throws Exception { 049 int capacity = 4 * 1024 * 1024; 050 ByteBufferArray array = new ByteBufferArray(capacity, ALLOC); 051 ByteBuff subBuf = ByteBuff.wrap(array.asSubByteBuffers(0, capacity)); 052 subBuf.position(capacity - 1);// Position to the last byte 053 assertTrue(subBuf.hasRemaining()); 054 // Read last byte 055 subBuf.get(); 056 assertFalse(subBuf.hasRemaining()); 057 } 058 059 @Test 060 public void testByteBufferCreation() throws Exception { 061 int capacity = 470 * 1021 * 1023; 062 ByteBufferArray array = new ByteBufferArray(capacity, ALLOC); 063 assertEquals(118, array.buffers.length); 064 for (int i = 0; i < array.buffers.length; i++) { 065 assertEquals(ByteBufferArray.DEFAULT_BUFFER_SIZE, array.buffers[i].capacity()); 066 } 067 } 068 069 @Test 070 public void testByteBufferCreation1() throws Exception { 071 long cap = 7 * 1024L * 1024L; 072 int bufferSize = ByteBufferArray.getBufferSize(cap), bufferCount = 25; 073 ByteBufferArray array = new ByteBufferArray(bufferSize, bufferCount, 16, cap, ALLOC); 074 for (int i = 0; i < array.buffers.length; i++) { 075 assertEquals(458752, array.buffers[i].capacity()); 076 } 077 } 078 079 private static void fill(ByteBuff buf, byte val) { 080 for (int i = buf.position(); i < buf.limit(); i++) { 081 buf.put(i, val); 082 } 083 } 084 085 private ByteBuff createByteBuff(int len) { 086 assert len >= 0; 087 int pos = len == 0 ? 0 : ThreadLocalRandom.current().nextInt(len); 088 ByteBuff b = ByteBuff.wrap(ByteBuffer.allocate(2 * len)); 089 b.position(pos).limit(pos + len); 090 return b; 091 } 092 093 private interface Call { 094 void run() throws IOException; 095 } 096 097 @SuppressWarnings("TryFailThrowable") 098 private void expectedAssert(Call r) throws IOException { 099 try { 100 r.run(); 101 fail(); 102 } catch (AssertionError e) { 103 // Ignore 104 } 105 } 106 107 @Test 108 public void testArrayIO() throws IOException { 109 int cap = 9 * 1024 * 1024, bufferSize = ByteBufferArray.getBufferSize(cap); 110 ByteBufferArray array = new ByteBufferArray(cap, ALLOC); 111 testReadAndWrite(array, 0, 512, (byte) 2); 112 testReadAndWrite(array, cap - 512, 512, (byte) 3); 113 testReadAndWrite(array, 4 * 1024 * 1024, 5 * 1024 * 1024, (byte) 4); 114 testReadAndWrite(array, 256, 256, (byte) 5); 115 testReadAndWrite(array, 257, 513, (byte) 6); 116 testReadAndWrite(array, 0, cap, (byte) 7); 117 testReadAndWrite(array, cap, 0, (byte) 8); 118 testReadAndWrite(array, cap - 1, 1, (byte) 9); 119 testReadAndWrite(array, cap - 2, 2, (byte) 10); 120 121 expectedAssert(() -> testReadAndWrite(array, cap - 2, 3, (byte) 11)); 122 expectedAssert(() -> testReadAndWrite(array, cap + 1, 0, (byte) 12)); 123 expectedAssert(() -> testReadAndWrite(array, 0, cap + 1, (byte) 12)); 124 expectedAssert(() -> testReadAndWrite(array, -1, 0, (byte) 13)); 125 expectedAssert(() -> testReadAndWrite(array, 0, -23, (byte) 14)); 126 expectedAssert(() -> testReadAndWrite(array, 0, 0, (byte) 15)); 127 expectedAssert(() -> testReadAndWrite(array, 4096, cap - 4096 + 1, (byte) 16)); 128 129 testAsSubByteBuff(array, 0, cap, true); 130 testAsSubByteBuff(array, 0, 0, false); 131 testAsSubByteBuff(array, 0, 1, false); 132 testAsSubByteBuff(array, 0, bufferSize - 1, false); 133 testAsSubByteBuff(array, 0, bufferSize, false); 134 testAsSubByteBuff(array, 0, bufferSize + 1, true); 135 testAsSubByteBuff(array, 0, 2 * bufferSize, true); 136 testAsSubByteBuff(array, 0, 5 * bufferSize, true); 137 testAsSubByteBuff(array, cap - bufferSize - 1, bufferSize, true); 138 testAsSubByteBuff(array, cap - bufferSize, bufferSize, false); 139 testAsSubByteBuff(array, cap - bufferSize, 0, false); 140 testAsSubByteBuff(array, cap - bufferSize, 1, false); 141 testAsSubByteBuff(array, cap - bufferSize, bufferSize - 1, false); 142 testAsSubByteBuff(array, cap - 2 * bufferSize, 2 * bufferSize, true); 143 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize + 1, true); 144 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize - 1, false); 145 testAsSubByteBuff(array, cap - 2 * bufferSize, 0, false); 146 147 expectedAssert(() -> testAsSubByteBuff(array, 0, cap + 1, false)); 148 expectedAssert(() -> testAsSubByteBuff(array, 0, -1, false)); 149 expectedAssert(() -> testAsSubByteBuff(array, -1, -1, false)); 150 expectedAssert(() -> testAsSubByteBuff(array, cap - bufferSize, bufferSize + 1, false)); 151 expectedAssert(() -> testAsSubByteBuff(array, 2 * bufferSize, cap - 2 * bufferSize + 1, false)); 152 } 153 154 private void testReadAndWrite(ByteBufferArray array, int off, int dataSize, byte val) { 155 ByteBuff src = createByteBuff(dataSize); 156 int pos = src.position(), lim = src.limit(); 157 fill(src, val); 158 assertEquals(src.remaining(), dataSize); 159 try { 160 assertEquals(dataSize, array.write(off, src)); 161 assertEquals(0, src.remaining()); 162 } finally { 163 src.position(pos).limit(lim); 164 } 165 166 ByteBuff dst = createByteBuff(dataSize); 167 pos = dst.position(); 168 lim = dst.limit(); 169 try { 170 assertEquals(dataSize, array.read(off, dst)); 171 assertEquals(0, dst.remaining()); 172 } finally { 173 dst.position(pos).limit(lim); 174 } 175 assertByteBuffEquals(src, dst); 176 } 177 178 private void testAsSubByteBuff(ByteBufferArray array, int off, int len, boolean isMulti) { 179 ByteBuff ret = ByteBuff.wrap(array.asSubByteBuffers(off, len)); 180 if (isMulti) { 181 assertTrue(ret instanceof MultiByteBuff); 182 } else { 183 assertTrue(ret instanceof SingleByteBuff); 184 } 185 assertTrue(!ret.hasArray()); 186 assertEquals(len, ret.remaining()); 187 188 ByteBuff tmp = createByteBuff(len); 189 int pos = tmp.position(), lim = tmp.limit(); 190 try { 191 assertEquals(len, array.read(off, tmp)); 192 assertEquals(0, tmp.remaining()); 193 } finally { 194 tmp.position(pos).limit(lim); 195 } 196 197 assertByteBuffEquals(ret, tmp); 198 } 199 200 private void assertByteBuffEquals(ByteBuff a, ByteBuff b) { 201 assertEquals(a.remaining(), b.remaining()); 202 for (int i = a.position(), j = b.position(); i < a.limit(); i++, j++) { 203 assertEquals(a.get(i), b.get(j)); 204 } 205 } 206}