| 
 | 1 | +/**  | 
 | 2 | + * Licensed to the Apache Software Foundation (ASF) under one  | 
 | 3 | + * or more contributor license agreements.  See the NOTICE file  | 
 | 4 | + * distributed with this work for additional information  | 
 | 5 | + * regarding copyright ownership.  The ASF licenses this file  | 
 | 6 | + * to you under the Apache License, Version 2.0 (the  | 
 | 7 | + * "License"); you may not use this file except in compliance  | 
 | 8 | + * with the License.  You may obtain a copy of the License at  | 
 | 9 | + *  | 
 | 10 | + *     http://www.apache.org/licenses/LICENSE-2.0  | 
 | 11 | + *  | 
 | 12 | + * Unless required by applicable law or agreed to in writing, software  | 
 | 13 | + * distributed under the License is distributed on an "AS IS" BASIS,  | 
 | 14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
 | 15 | + * See the License for the specific language governing permissions and  | 
 | 16 | + * limitations under the License.  | 
 | 17 | + */  | 
 | 18 | +package org.apache.hadoop.hbase.regionserver.storefiletracker;  | 
 | 19 | + | 
 | 20 | +import static org.junit.Assert.assertNull;  | 
 | 21 | +import static org.junit.Assert.assertThrows;  | 
 | 22 | +import static org.mockito.Mockito.mock;  | 
 | 23 | +import static org.mockito.Mockito.when;  | 
 | 24 | + | 
 | 25 | +import java.io.IOException;  | 
 | 26 | +import org.apache.hadoop.fs.FSDataInputStream;  | 
 | 27 | +import org.apache.hadoop.fs.FSDataOutputStream;  | 
 | 28 | +import org.apache.hadoop.fs.FileStatus;  | 
 | 29 | +import org.apache.hadoop.fs.FileSystem;  | 
 | 30 | +import org.apache.hadoop.fs.Path;  | 
 | 31 | +import org.apache.hadoop.hbase.HBaseClassTestRule;  | 
 | 32 | +import org.apache.hadoop.hbase.HBaseCommonTestingUtility;  | 
 | 33 | +import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;  | 
 | 34 | +import org.apache.hadoop.hbase.regionserver.StoreContext;  | 
 | 35 | +import org.apache.hadoop.hbase.testclassification.RegionServerTests;  | 
 | 36 | +import org.apache.hadoop.hbase.testclassification.SmallTests;  | 
 | 37 | +import org.apache.hadoop.hbase.util.Bytes;  | 
 | 38 | +import org.junit.AfterClass;  | 
 | 39 | +import org.junit.Before;  | 
 | 40 | +import org.junit.ClassRule;  | 
 | 41 | +import org.junit.Rule;  | 
 | 42 | +import org.junit.Test;  | 
 | 43 | +import org.junit.experimental.categories.Category;  | 
 | 44 | +import org.junit.rules.TestName;  | 
 | 45 | +import org.slf4j.Logger;  | 
 | 46 | +import org.slf4j.LoggerFactory;  | 
 | 47 | + | 
 | 48 | +import org.apache.hbase.thirdparty.com.google.common.io.ByteStreams;  | 
 | 49 | + | 
 | 50 | +import org.apache.hadoop.hbase.shaded.protobuf.generated.StoreFileTrackerProtos.StoreFileList;  | 
 | 51 | + | 
 | 52 | +@Category({ RegionServerTests.class, SmallTests.class })  | 
 | 53 | +public class TestStoreFileListFile {  | 
 | 54 | + | 
 | 55 | +  @ClassRule  | 
 | 56 | +  public static final HBaseClassTestRule CLASS_RULE =  | 
 | 57 | +    HBaseClassTestRule.forClass(TestStoreFileListFile.class);  | 
 | 58 | + | 
 | 59 | +  private static final Logger LOG = LoggerFactory.getLogger(TestStoreFileListFile.class);  | 
 | 60 | + | 
 | 61 | +  private static final HBaseCommonTestingUtility UTIL = new HBaseCommonTestingUtility();  | 
 | 62 | + | 
 | 63 | +  private Path testDir;  | 
 | 64 | + | 
 | 65 | +  private StoreFileListFile storeFileListFile;  | 
 | 66 | + | 
 | 67 | +  @Rule  | 
 | 68 | +  public TestName name = new TestName();  | 
 | 69 | + | 
 | 70 | +  @Before  | 
 | 71 | +  public void setUp() throws IOException {  | 
 | 72 | +    testDir = UTIL.getDataTestDir(name.getMethodName());  | 
 | 73 | +    HRegionFileSystem hfs = mock(HRegionFileSystem.class);  | 
 | 74 | +    when(hfs.getFileSystem()).thenReturn(FileSystem.get(UTIL.getConfiguration()));  | 
 | 75 | +    StoreContext ctx = StoreContext.getBuilder().withFamilyStoreDirectoryPath(testDir)  | 
 | 76 | +      .withRegionFileSystem(hfs).build();  | 
 | 77 | +    storeFileListFile = new StoreFileListFile(ctx);  | 
 | 78 | +  }  | 
 | 79 | + | 
 | 80 | +  @AfterClass  | 
 | 81 | +  public static void tearDown() {  | 
 | 82 | +    UTIL.cleanupTestDir();  | 
 | 83 | +  }  | 
 | 84 | + | 
 | 85 | +  @Test  | 
 | 86 | +  public void testEmptyLoad() throws IOException {  | 
 | 87 | +    assertNull(storeFileListFile.load());  | 
 | 88 | +  }  | 
 | 89 | + | 
 | 90 | +  private FileStatus getOnlyTrackerFile(FileSystem fs) throws IOException {  | 
 | 91 | +    return fs.listStatus(new Path(testDir, StoreFileListFile.TRACK_FILE_DIR))[0];  | 
 | 92 | +  }  | 
 | 93 | + | 
 | 94 | +  private byte[] readAll(FileSystem fs, Path file) throws IOException {  | 
 | 95 | +    try (FSDataInputStream in = fs.open(file)) {  | 
 | 96 | +      return ByteStreams.toByteArray(in);  | 
 | 97 | +    }  | 
 | 98 | +  }  | 
 | 99 | + | 
 | 100 | +  private void write(FileSystem fs, Path file, byte[] buf, int off, int len) throws IOException {  | 
 | 101 | +    try (FSDataOutputStream out = fs.create(file, true)) {  | 
 | 102 | +      out.write(buf, off, len);  | 
 | 103 | +    }  | 
 | 104 | +  }  | 
 | 105 | + | 
 | 106 | +  @Test  | 
 | 107 | +  public void testLoadPartial() throws IOException {  | 
 | 108 | +    StoreFileList.Builder builder = StoreFileList.newBuilder();  | 
 | 109 | +    storeFileListFile.update(builder);  | 
 | 110 | +    FileSystem fs = FileSystem.get(UTIL.getConfiguration());  | 
 | 111 | +    FileStatus trackerFileStatus = getOnlyTrackerFile(fs);  | 
 | 112 | +    // truncate it so we do not have enough data  | 
 | 113 | +    LOG.info("Truncate file {} with size {} to {}", trackerFileStatus.getPath(),  | 
 | 114 | +      trackerFileStatus.getLen(), trackerFileStatus.getLen() / 2);  | 
 | 115 | +    byte[] content = readAll(fs, trackerFileStatus.getPath());  | 
 | 116 | +    write(fs, trackerFileStatus.getPath(), content, 0, content.length / 2);  | 
 | 117 | +    assertNull(storeFileListFile.load());  | 
 | 118 | +  }  | 
 | 119 | + | 
 | 120 | +  private void writeInt(byte[] buf, int off, int value) {  | 
 | 121 | +    byte[] b = Bytes.toBytes(value);  | 
 | 122 | +    for (int i = 0; i < 4; i++) {  | 
 | 123 | +      buf[off + i] = b[i];  | 
 | 124 | +    }  | 
 | 125 | +  }  | 
 | 126 | + | 
 | 127 | +  @Test  | 
 | 128 | +  public void testZeroFileLength() throws IOException {  | 
 | 129 | +    StoreFileList.Builder builder = StoreFileList.newBuilder();  | 
 | 130 | +    storeFileListFile.update(builder);  | 
 | 131 | +    FileSystem fs = FileSystem.get(UTIL.getConfiguration());  | 
 | 132 | +    FileStatus trackerFileStatus = getOnlyTrackerFile(fs);  | 
 | 133 | +    // write a zero length  | 
 | 134 | +    byte[] content = readAll(fs, trackerFileStatus.getPath());  | 
 | 135 | +    writeInt(content, 0, 0);  | 
 | 136 | +    write(fs, trackerFileStatus.getPath(), content, 0, content.length);  | 
 | 137 | +    assertThrows(IOException.class, () -> storeFileListFile.load());  | 
 | 138 | +  }  | 
 | 139 | + | 
 | 140 | +  @Test  | 
 | 141 | +  public void testBigFileLength() throws IOException {  | 
 | 142 | +    StoreFileList.Builder builder = StoreFileList.newBuilder();  | 
 | 143 | +    storeFileListFile.update(builder);  | 
 | 144 | +    FileSystem fs = FileSystem.get(UTIL.getConfiguration());  | 
 | 145 | +    FileStatus trackerFileStatus = getOnlyTrackerFile(fs);  | 
 | 146 | +    // write a large length  | 
 | 147 | +    byte[] content = readAll(fs, trackerFileStatus.getPath());  | 
 | 148 | +    writeInt(content, 0, 128 * 1024 * 1024);  | 
 | 149 | +    write(fs, trackerFileStatus.getPath(), content, 0, content.length);  | 
 | 150 | +    assertThrows(IOException.class, () -> storeFileListFile.load());  | 
 | 151 | +  }  | 
 | 152 | + | 
 | 153 | +  @Test  | 
 | 154 | +  public void testChecksumMismatch() throws IOException {  | 
 | 155 | +    StoreFileList.Builder builder = StoreFileList.newBuilder();  | 
 | 156 | +    storeFileListFile.update(builder);  | 
 | 157 | +    FileSystem fs = FileSystem.get(UTIL.getConfiguration());  | 
 | 158 | +    FileStatus trackerFileStatus = getOnlyTrackerFile(fs);  | 
 | 159 | +    // flip one byte  | 
 | 160 | +    byte[] content = readAll(fs, trackerFileStatus.getPath());  | 
 | 161 | +    content[5] = (byte) ~content[5];  | 
 | 162 | +    write(fs, trackerFileStatus.getPath(), content, 0, content.length);  | 
 | 163 | +    assertThrows(IOException.class, () -> storeFileListFile.load());  | 
 | 164 | +  }  | 
 | 165 | +}  | 
0 commit comments