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 private void expectedAssert(Call r) throws IOException { 098 boolean asserted = true; 099 try { 100 r.run(); 101 asserted = false; 102 } catch (AssertionError e) { 103 // Expected 104 } 105 if (!asserted) { 106 fail("Failed to assert expected assertion"); 107 } 108 } 109 110 @Test 111 public void testArrayIO() throws IOException { 112 int cap = 9 * 1024 * 1024, bufferSize = ByteBufferArray.getBufferSize(cap); 113 ByteBufferArray array = new ByteBufferArray(cap, ALLOC); 114 testReadAndWrite(array, 0, 512, (byte) 2); 115 testReadAndWrite(array, cap - 512, 512, (byte) 3); 116 testReadAndWrite(array, 4 * 1024 * 1024, 5 * 1024 * 1024, (byte) 4); 117 testReadAndWrite(array, 256, 256, (byte) 5); 118 testReadAndWrite(array, 257, 513, (byte) 6); 119 testReadAndWrite(array, 0, cap, (byte) 7); 120 testReadAndWrite(array, cap, 0, (byte) 8); 121 testReadAndWrite(array, cap - 1, 1, (byte) 9); 122 testReadAndWrite(array, cap - 2, 2, (byte) 10); 123 124 expectedAssert(() -> testReadAndWrite(array, cap - 2, 3, (byte) 11)); 125 expectedAssert(() -> testReadAndWrite(array, 0, cap + 1, (byte) 12)); 126 expectedAssert(() -> testReadAndWrite(array, 0, -23, (byte) 14)); 127 expectedAssert(() -> testReadAndWrite(array, 4096, cap - 4096 + 1, (byte) 16)); 128 129 // XXX: These cases were apparently expected to assert but expectedAssert() was 130 // incorrectly implemented as a no-op. Fix these? 131 // expectedAssert(() -> testReadAndWrite(array, cap + 1, 0, (byte) 12)); 132 // expectedAssert(() -> testReadAndWrite(array, -1, 0, (byte) 13)); 133 // expectedAssert(() -> testReadAndWrite(array, 0, 0, (byte) 15)); 134 135 testAsSubByteBuff(array, 0, cap, true); 136 testAsSubByteBuff(array, 0, 0, false); 137 testAsSubByteBuff(array, 0, 1, false); 138 testAsSubByteBuff(array, 0, bufferSize - 1, false); 139 testAsSubByteBuff(array, 0, bufferSize, false); 140 testAsSubByteBuff(array, 0, bufferSize + 1, true); 141 testAsSubByteBuff(array, 0, 2 * bufferSize, true); 142 testAsSubByteBuff(array, 0, 5 * bufferSize, true); 143 testAsSubByteBuff(array, cap - bufferSize - 1, bufferSize, true); 144 testAsSubByteBuff(array, cap - bufferSize, bufferSize, false); 145 testAsSubByteBuff(array, cap - bufferSize, 0, false); 146 testAsSubByteBuff(array, cap - bufferSize, 1, false); 147 testAsSubByteBuff(array, cap - bufferSize, bufferSize - 1, false); 148 testAsSubByteBuff(array, cap - 2 * bufferSize, 2 * bufferSize, true); 149 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize + 1, true); 150 testAsSubByteBuff(array, cap - 2 * bufferSize, bufferSize - 1, false); 151 testAsSubByteBuff(array, cap - 2 * bufferSize, 0, false); 152 153 expectedAssert(() -> testAsSubByteBuff(array, 0, cap + 1, false)); 154 expectedAssert(() -> testAsSubByteBuff(array, 0, -1, false)); 155 expectedAssert(() -> testAsSubByteBuff(array, -1, -1, false)); 156 expectedAssert(() -> testAsSubByteBuff(array, cap - bufferSize, bufferSize + 1, false)); 157 expectedAssert(() -> testAsSubByteBuff(array, 2 * bufferSize, cap - 2 * bufferSize + 1, false)); 158 } 159 160 private void testReadAndWrite(ByteBufferArray array, int off, int dataSize, byte val) { 161 ByteBuff src = createByteBuff(dataSize); 162 int pos = src.position(), lim = src.limit(); 163 fill(src, val); 164 assertEquals(src.remaining(), dataSize); 165 try { 166 assertEquals(dataSize, array.write(off, src)); 167 assertEquals(0, src.remaining()); 168 } finally { 169 src.position(pos).limit(lim); 170 } 171 172 ByteBuff dst = createByteBuff(dataSize); 173 pos = dst.position(); 174 lim = dst.limit(); 175 try { 176 assertEquals(dataSize, array.read(off, dst)); 177 assertEquals(0, dst.remaining()); 178 } finally { 179 dst.position(pos).limit(lim); 180 } 181 assertByteBuffEquals(src, dst); 182 } 183 184 private void testAsSubByteBuff(ByteBufferArray array, int off, int len, boolean isMulti) { 185 ByteBuff ret = ByteBuff.wrap(array.asSubByteBuffers(off, len)); 186 if (isMulti) { 187 assertTrue(ret instanceof MultiByteBuff); 188 } else { 189 assertTrue(ret instanceof SingleByteBuff); 190 } 191 assertTrue(!ret.hasArray()); 192 assertEquals(len, ret.remaining()); 193 194 ByteBuff tmp = createByteBuff(len); 195 int pos = tmp.position(), lim = tmp.limit(); 196 try { 197 assertEquals(len, array.read(off, tmp)); 198 assertEquals(0, tmp.remaining()); 199 } finally { 200 tmp.position(pos).limit(lim); 201 } 202 203 assertByteBuffEquals(ret, tmp); 204 } 205 206 private void assertByteBuffEquals(ByteBuff a, ByteBuff b) { 207 assertEquals(a.remaining(), b.remaining()); 208 for (int i = a.position(), j = b.position(); i < a.limit(); i++, j++) { 209 assertEquals(a.get(i), b.get(j)); 210 } 211 } 212}