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.io.hfile.bucket;
019
020import static org.junit.Assert.assertTrue;
021
022import java.io.IOException;
023import java.nio.ByteBuffer;
024import org.apache.hadoop.hbase.HBaseClassTestRule;
025import org.apache.hadoop.hbase.io.hfile.Cacheable;
026import org.apache.hadoop.hbase.io.hfile.Cacheable.MemoryType;
027import org.apache.hadoop.hbase.io.hfile.CacheableDeserializer;
028import org.apache.hadoop.hbase.nio.ByteBuff;
029import org.apache.hadoop.hbase.testclassification.IOTests;
030import org.apache.hadoop.hbase.testclassification.SmallTests;
031import org.junit.ClassRule;
032import org.junit.Test;
033import org.junit.experimental.categories.Category;
034
035/**
036 * Basic test for {@link ByteBufferIOEngine}
037 */
038@Category({IOTests.class, SmallTests.class})
039public class TestByteBufferIOEngine {
040
041  @ClassRule
042  public static final HBaseClassTestRule CLASS_RULE =
043      HBaseClassTestRule.forClass(TestByteBufferIOEngine.class);
044
045  @Test
046  public void testByteBufferIOEngine() throws Exception {
047    int capacity = 32 * 1024 * 1024; // 32 MB
048    int testNum = 100;
049    int maxBlockSize = 64 * 1024;
050    ByteBufferIOEngine ioEngine = new ByteBufferIOEngine(capacity);
051    int testOffsetAtStartNum = testNum / 10;
052    int testOffsetAtEndNum = testNum / 10;
053    for (int i = 0; i < testNum; i++) {
054      byte val = (byte) (Math.random() * 255);
055      int blockSize = (int) (Math.random() * maxBlockSize);
056      if (blockSize == 0) {
057        blockSize = 1;
058      }
059      byte[] byteArray = new byte[blockSize];
060      for (int j = 0; j < byteArray.length; ++j) {
061        byteArray[j] = val;
062      }
063      ByteBuffer srcBuffer = ByteBuffer.wrap(byteArray);
064      int offset = 0;
065      if (testOffsetAtStartNum > 0) {
066        testOffsetAtStartNum--;
067        offset = 0;
068      } else if (testOffsetAtEndNum > 0) {
069        testOffsetAtEndNum--;
070        offset = capacity - blockSize;
071      } else {
072        offset = (int) (Math.random() * (capacity - maxBlockSize));
073      }
074      ioEngine.write(srcBuffer, offset);
075      BufferGrabbingDeserializer deserializer = new BufferGrabbingDeserializer();
076      ioEngine.read(offset, blockSize, deserializer);
077      ByteBuff dstBuffer = deserializer.buf;
078      for (int j = 0; j < byteArray.length; ++j) {
079        assertTrue(byteArray[j] == dstBuffer.get(j));
080      }
081    }
082    assert testOffsetAtStartNum == 0;
083    assert testOffsetAtEndNum == 0;
084  }
085
086  /**
087   * A CacheableDeserializer implementation which just store reference to the {@link ByteBuff} to be
088   * deserialized. Use {@link #getDeserializedByteBuff()} to get this reference.
089   */
090  static class BufferGrabbingDeserializer implements CacheableDeserializer<Cacheable> {
091    private ByteBuff buf;
092
093    @Override
094    public Cacheable deserialize(ByteBuff b) throws IOException {
095      return null;
096    }
097
098    @Override
099    public Cacheable deserialize(final ByteBuff b, boolean reuse, MemoryType memType)
100        throws IOException {
101      this.buf = b;
102      return null;
103    }
104
105    @Override
106    public int getDeserialiserIdentifier() {
107      return 0;
108    }
109
110    public ByteBuff getDeserializedByteBuff() {
111      return this.buf;
112    }
113  }
114
115  @Test
116  public void testByteBufferIOEngineWithMBB() throws Exception {
117    int capacity = 32 * 1024 * 1024; // 32 MB
118    int testNum = 100;
119    int maxBlockSize = 64 * 1024;
120    ByteBufferIOEngine ioEngine = new ByteBufferIOEngine(capacity);
121    int testOffsetAtStartNum = testNum / 10;
122    int testOffsetAtEndNum = testNum / 10;
123    for (int i = 0; i < testNum; i++) {
124      byte val = (byte) (Math.random() * 255);
125      int blockSize = (int) (Math.random() * maxBlockSize);
126      if (blockSize == 0) {
127        blockSize = 1;
128      }
129      byte[] byteArray = new byte[blockSize];
130      for (int j = 0; j < byteArray.length; ++j) {
131        byteArray[j] = val;
132      }
133      ByteBuffer srcBuffer = ByteBuffer.wrap(byteArray);
134      int offset = 0;
135      if (testOffsetAtStartNum > 0) {
136        testOffsetAtStartNum--;
137        offset = 0;
138      } else if (testOffsetAtEndNum > 0) {
139        testOffsetAtEndNum--;
140        offset = capacity - blockSize;
141      } else {
142        offset = (int) (Math.random() * (capacity - maxBlockSize));
143      }
144      ioEngine.write(srcBuffer, offset);
145      BufferGrabbingDeserializer deserializer = new BufferGrabbingDeserializer();
146      ioEngine.read(offset, blockSize, deserializer);
147      ByteBuff dstBuffer = deserializer.buf;
148      for (int j = 0; j < byteArray.length; ++j) {
149        assertTrue(srcBuffer.get(j) == dstBuffer.get(j));
150      }
151    }
152    assert testOffsetAtStartNum == 0;
153    assert testOffsetAtEndNum == 0;
154  }
155}