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.assertArrayEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertNotNull;
023
024import java.io.File;
025import java.io.IOException;
026import java.nio.ByteBuffer;
027import java.nio.channels.FileChannel;
028import java.util.ArrayList;
029import java.util.List;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.io.hfile.bucket.TestByteBufferIOEngine.BufferGrabbingDeserializer;
032import org.apache.hadoop.hbase.nio.ByteBuff;
033import org.apache.hadoop.hbase.testclassification.IOTests;
034import org.apache.hadoop.hbase.testclassification.SmallTests;
035import org.junit.After;
036import org.junit.Before;
037import org.junit.ClassRule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040
041/**
042 * Basic test for {@link FileIOEngine}
043 */
044@Category({IOTests.class, SmallTests.class})
045public class TestFileIOEngine {
046
047  @ClassRule
048  public static final HBaseClassTestRule CLASS_RULE =
049      HBaseClassTestRule.forClass(TestFileIOEngine.class);
050
051  private static final long TOTAL_CAPACITY = 6 * 1024 * 1024; // 6 MB
052  private static final String[] FILE_PATHS = {"testFileIOEngine1", "testFileIOEngine2",
053      "testFileIOEngine3"};
054  private static final long SIZE_PER_FILE = TOTAL_CAPACITY / FILE_PATHS.length; // 2 MB per File
055  private final static List<Long> boundaryStartPositions = new ArrayList<Long>();
056  private final static List<Long> boundaryStopPositions = new ArrayList<Long>();
057
058  private FileIOEngine fileIOEngine;
059
060  static {
061    boundaryStartPositions.add(0L);
062    for (int i = 1; i < FILE_PATHS.length; i++) {
063      boundaryStartPositions.add(SIZE_PER_FILE * i - 1);
064      boundaryStartPositions.add(SIZE_PER_FILE * i);
065      boundaryStartPositions.add(SIZE_PER_FILE * i + 1);
066    }
067    for (int i = 1; i < FILE_PATHS.length; i++) {
068      boundaryStopPositions.add(SIZE_PER_FILE * i - 1);
069      boundaryStopPositions.add(SIZE_PER_FILE * i);
070      boundaryStopPositions.add(SIZE_PER_FILE * i + 1);
071    }
072    boundaryStopPositions.add(SIZE_PER_FILE * FILE_PATHS.length - 1);
073  }
074
075  @Before
076  public void setUp() throws IOException {
077    fileIOEngine = new FileIOEngine(TOTAL_CAPACITY, false, FILE_PATHS);
078  }
079
080  @After
081  public void cleanUp() {
082    fileIOEngine.shutdown();
083    for (String filePath : FILE_PATHS) {
084      File file = new File(filePath);
085      if (file.exists()) {
086        file.delete();
087      }
088    }
089  }
090
091  @Test
092  public void testFileIOEngine() throws IOException {
093    for (int i = 0; i < 500; i++) {
094      int len = (int) Math.floor(Math.random() * 100) + 1;
095      long offset = (long) Math.floor(Math.random() * TOTAL_CAPACITY % (TOTAL_CAPACITY - len));
096      if (i < boundaryStartPositions.size()) {
097        // make the boundary start positon
098        offset = boundaryStartPositions.get(i);
099      } else if ((i - boundaryStartPositions.size()) < boundaryStopPositions.size()) {
100        // make the boundary stop positon
101        offset = boundaryStopPositions.get(i - boundaryStartPositions.size()) - len + 1;
102      } else if (i % 2 == 0) {
103        // make the cross-files block writing/reading
104        offset = Math.max(1, i % FILE_PATHS.length) * SIZE_PER_FILE - len / 2;
105      }
106      byte[] data1 = new byte[len];
107      for (int j = 0; j < data1.length; ++j) {
108        data1[j] = (byte) (Math.random() * 255);
109      }
110      fileIOEngine.write(ByteBuffer.wrap(data1), offset);
111      BufferGrabbingDeserializer deserializer = new BufferGrabbingDeserializer();
112      fileIOEngine.read(offset, len, deserializer);
113      ByteBuff data2 = deserializer.getDeserializedByteBuff();
114      assertArrayEquals(data1, data2.array());
115    }
116  }
117
118  @Test
119  public void testFileIOEngineHandlesZeroLengthInput() throws IOException {
120    byte[] data1 = new byte[0];
121
122    fileIOEngine.write(ByteBuffer.wrap(data1), 0);
123    BufferGrabbingDeserializer deserializer = new BufferGrabbingDeserializer();
124    fileIOEngine.read(0, 0, deserializer);
125    ByteBuff data2 = deserializer.getDeserializedByteBuff();
126    assertArrayEquals(data1, data2.array());
127  }
128
129  @Test
130  public void testClosedChannelException() throws IOException {
131    fileIOEngine.closeFileChannels();
132    int len = 5;
133    long offset = 0L;
134    byte[] data1 = new byte[len];
135    for (int j = 0; j < data1.length; ++j) {
136      data1[j] = (byte) (Math.random() * 255);
137    }
138    fileIOEngine.write(ByteBuffer.wrap(data1), offset);
139    BufferGrabbingDeserializer deserializer = new BufferGrabbingDeserializer();
140    fileIOEngine.read(offset, len, deserializer);
141    ByteBuff data2 = deserializer.getDeserializedByteBuff();
142    assertArrayEquals(data1, data2.array());
143  }
144
145  @Test
146  public void testRefreshFileConnectionClosesConnections() throws IOException {
147    FileChannel fileChannel = fileIOEngine.getFileChannels()[0];
148    assertNotNull(fileChannel);
149    fileIOEngine.refreshFileConnection(0);
150    assertFalse(fileChannel.isOpen());
151  }
152}