| 
20 | 20 | import static org.junit.Assert.assertEquals;  | 
21 | 21 | import static org.junit.Assert.assertFalse;  | 
22 | 22 | import static org.junit.Assert.assertTrue;  | 
 | 23 | +import static org.mockito.ArgumentMatchers.any;  | 
 | 24 | +import static org.mockito.Mockito.mock;  | 
 | 25 | +import static org.mockito.Mockito.times;  | 
 | 26 | +import static org.mockito.Mockito.verify;  | 
 | 27 | +import static org.mockito.Mockito.when;  | 
23 | 28 | 
 
  | 
24 | 29 | import java.io.IOException;  | 
25 | 30 | import java.security.PrivilegedExceptionAction;  | 
26 | 31 | import java.util.ArrayList;  | 
 | 32 | +import java.util.Collection;  | 
27 | 33 | import java.util.Collections;  | 
28 | 34 | import java.util.List;  | 
29 | 35 | import java.util.stream.Collectors;  | 
 | 
39 | 45 | import org.apache.hadoop.hbase.Stoppable;  | 
40 | 46 | import org.apache.hadoop.hbase.TableName;  | 
41 | 47 | import org.apache.hadoop.hbase.client.Admin;  | 
 | 48 | +import org.apache.hadoop.hbase.client.RegionInfo;  | 
42 | 49 | import org.apache.hadoop.hbase.client.Table;  | 
43 | 50 | import org.apache.hadoop.hbase.master.cleaner.DirScanPool;  | 
44 | 51 | import org.apache.hadoop.hbase.master.cleaner.HFileCleaner;  | 
45 | 52 | import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;  | 
46 | 53 | import org.apache.hadoop.hbase.regionserver.HRegion;  | 
47 | 54 | import org.apache.hadoop.hbase.regionserver.HRegionServer;  | 
 | 55 | +import org.apache.hadoop.hbase.regionserver.HStoreFile;  | 
48 | 56 | import org.apache.hadoop.hbase.testclassification.MediumTests;  | 
49 | 57 | import org.apache.hadoop.hbase.testclassification.MiscTests;  | 
50 | 58 | import org.apache.hadoop.hbase.util.Bytes;  | 
 | 59 | +import org.apache.hadoop.hbase.util.CommonFSUtils;  | 
51 | 60 | import org.apache.hadoop.hbase.util.FSUtils;  | 
52 | 61 | import org.apache.hadoop.hbase.util.HFileArchiveTestingUtil;  | 
53 | 62 | import org.apache.hadoop.hbase.util.HFileArchiveUtil;  | 
 | 
62 | 71 | import org.junit.Test;  | 
63 | 72 | import org.junit.experimental.categories.Category;  | 
64 | 73 | import org.junit.rules.TestName;  | 
 | 74 | +import org.mockito.ArgumentCaptor;  | 
65 | 75 | import org.slf4j.Logger;  | 
66 | 76 | import org.slf4j.LoggerFactory;  | 
67 | 77 | 
 
  | 
@@ -123,6 +133,107 @@ public static void cleanupTest() throws Exception {  | 
123 | 133 |     POOL.shutdownNow();  | 
124 | 134 |   }  | 
125 | 135 | 
 
  | 
 | 136 | +  @Test  | 
 | 137 | +  public void testArchiveStoreFilesDifferentFileSystemsWallWithSchemaPlainRoot() throws Exception {  | 
 | 138 | +    String walDir = "mockFS://mockFSAuthority:9876/mockDir/wals/";  | 
 | 139 | +    String baseDir = FSUtils.getRootDir(UTIL.getConfiguration()).toString() + "/";  | 
 | 140 | +    testArchiveStoreFilesDifferentFileSystems(walDir, baseDir,  | 
 | 141 | +      HFileArchiver::archiveStoreFiles);  | 
 | 142 | +  }  | 
 | 143 | + | 
 | 144 | +  @Test  | 
 | 145 | +  public void testArchiveStoreFilesDifferentFileSystemsWallNullPlainRoot() throws Exception {  | 
 | 146 | +    String baseDir = FSUtils.getRootDir(UTIL.getConfiguration()).toString() + "/";  | 
 | 147 | +    testArchiveStoreFilesDifferentFileSystems(null, baseDir,  | 
 | 148 | +      HFileArchiver::archiveStoreFiles);  | 
 | 149 | +  }  | 
 | 150 | + | 
 | 151 | +  @Test  | 
 | 152 | +  public void testArchiveStoreFilesDifferentFileSystemsWallAndRootSame() throws Exception {  | 
 | 153 | +    String baseDir = FSUtils.getRootDir(UTIL.getConfiguration()).toString() + "/";  | 
 | 154 | +    testArchiveStoreFilesDifferentFileSystems("/hbase/wals/", baseDir,  | 
 | 155 | +      HFileArchiver::archiveStoreFiles);  | 
 | 156 | +  }  | 
 | 157 | + | 
 | 158 | +  private void testArchiveStoreFilesDifferentFileSystems(String walDir, String expectedBase,  | 
 | 159 | +    ArchivingFunction<Configuration, FileSystem, RegionInfo, Path, byte[],  | 
 | 160 | +      Collection<HStoreFile>> archivingFunction) throws IOException {  | 
 | 161 | +    FileSystem mockedFileSystem = mock(FileSystem.class);  | 
 | 162 | +    Configuration conf = new Configuration(UTIL.getConfiguration());  | 
 | 163 | +    if(walDir != null) {  | 
 | 164 | +      conf.set(CommonFSUtils.HBASE_WAL_DIR, walDir);  | 
 | 165 | +    }  | 
 | 166 | +    Path filePath = new Path("/mockDir/wals/mockFile");  | 
 | 167 | +    when(mockedFileSystem.getScheme()).thenReturn("mockFS");  | 
 | 168 | +    when(mockedFileSystem.mkdirs(any())).thenReturn(true);  | 
 | 169 | +    when(mockedFileSystem.exists(any())).thenReturn(true);  | 
 | 170 | +    RegionInfo mockedRegion = mock(RegionInfo.class);  | 
 | 171 | +    TableName tableName = TableName.valueOf("mockTable");  | 
 | 172 | +    when(mockedRegion.getTable()).thenReturn(tableName);  | 
 | 173 | +    when(mockedRegion.getEncodedName()).thenReturn("mocked-region-encoded-name");  | 
 | 174 | +    Path tableDir = new Path("mockFS://mockDir/tabledir");  | 
 | 175 | +    byte[] family = Bytes.toBytes("testfamily");  | 
 | 176 | +    HStoreFile mockedFile = mock(HStoreFile.class);  | 
 | 177 | +    List<HStoreFile> list = new ArrayList<>();  | 
 | 178 | +    list.add(mockedFile);  | 
 | 179 | +    when(mockedFile.getPath()).thenReturn(filePath);  | 
 | 180 | +    when(mockedFileSystem.rename(any(),any())).thenReturn(true);  | 
 | 181 | +    archivingFunction.apply(conf, mockedFileSystem, mockedRegion, tableDir, family, list);  | 
 | 182 | +    ArgumentCaptor<Path> pathCaptor = ArgumentCaptor.forClass(Path.class);  | 
 | 183 | +    verify(mockedFileSystem, times(2)).rename(pathCaptor.capture(), any());  | 
 | 184 | +    String expectedDir = expectedBase +  | 
 | 185 | +      "archive/data/default/mockTable/mocked-region-encoded-name/testfamily/mockFile";  | 
 | 186 | +    assertTrue(pathCaptor.getAllValues().get(0).toString().equals(expectedDir));  | 
 | 187 | +  }  | 
 | 188 | + | 
 | 189 | +  @FunctionalInterface  | 
 | 190 | +  private interface ArchivingFunction<Configuration, FS, Region, Dir, Family, Files> {  | 
 | 191 | +    void apply(Configuration config, FS fs, Region region, Dir dir, Family family, Files files)  | 
 | 192 | +      throws IOException;  | 
 | 193 | +  }  | 
 | 194 | + | 
 | 195 | +  @Test  | 
 | 196 | +  public void testArchiveRecoveredEditsWalDirNull() throws Exception {  | 
 | 197 | +    testArchiveRecoveredEditsWalDirNullOrSame(null);  | 
 | 198 | +  }  | 
 | 199 | + | 
 | 200 | +  @Test  | 
 | 201 | +  public void testArchiveRecoveredEditsWalDirSameFsStoreFiles() throws Exception {  | 
 | 202 | +    testArchiveRecoveredEditsWalDirNullOrSame("/wal-dir");  | 
 | 203 | +  }  | 
 | 204 | + | 
 | 205 | +  private void testArchiveRecoveredEditsWalDirNullOrSame(String walDir) throws Exception {  | 
 | 206 | +    String originalRootDir = UTIL.getConfiguration().get(HConstants.HBASE_DIR);  | 
 | 207 | +    try {  | 
 | 208 | +      String baseDir = "mockFS://mockFSAuthority:9876/hbase/";  | 
 | 209 | +      UTIL.getConfiguration().set(HConstants.HBASE_DIR, baseDir);  | 
 | 210 | +      testArchiveStoreFilesDifferentFileSystems(walDir, baseDir,  | 
 | 211 | +        (conf, fs, region, dir, family, list) -> HFileArchiver  | 
 | 212 | +          .archiveRecoveredEdits(conf, fs, region, family, list));  | 
 | 213 | +    } finally {  | 
 | 214 | +      UTIL.getConfiguration().set(HConstants.HBASE_DIR, originalRootDir);  | 
 | 215 | +    }  | 
 | 216 | +  }  | 
 | 217 | + | 
 | 218 | +  @Test(expected = IOException.class)  | 
 | 219 | +  public void testArchiveRecoveredEditsWrongFS() throws Exception {  | 
 | 220 | +    String baseDir = FSUtils.getRootDir(UTIL.getConfiguration()).toString() + "/";  | 
 | 221 | +    //Internally, testArchiveStoreFilesDifferentFileSystems will pass a "mockedFS"  | 
 | 222 | +    // to HFileArchiver.archiveRecoveredEdits, but since wal-dir is supposedly on same FS  | 
 | 223 | +    // as root dir it would lead to conflicting FSes and an IOException is expected.  | 
 | 224 | +    testArchiveStoreFilesDifferentFileSystems("/wal-dir", baseDir,  | 
 | 225 | +      (conf, fs, region, dir, family, list) -> HFileArchiver  | 
 | 226 | +        .archiveRecoveredEdits(conf, fs, region, family, list));  | 
 | 227 | +  }  | 
 | 228 | + | 
 | 229 | +  @Test  | 
 | 230 | +  public void testArchiveRecoveredEditsWalDirDifferentFS() throws Exception {  | 
 | 231 | +    String walDir = "mockFS://mockFSAuthority:9876/mockDir/wals/";  | 
 | 232 | +    testArchiveStoreFilesDifferentFileSystems(walDir, walDir,  | 
 | 233 | +      (conf, fs, region, dir, family, list) ->  | 
 | 234 | +        HFileArchiver.archiveRecoveredEdits(conf, fs, region, family, list));  | 
 | 235 | +  }  | 
 | 236 | + | 
126 | 237 |   @Test  | 
127 | 238 |   public void testRemoveRegionDirOnArchive() throws Exception {  | 
128 | 239 |     final TableName tableName = TableName.valueOf(name.getMethodName());  | 
 | 
0 commit comments