From 82f6127d73a2472d83f24eff12a3d78d133eee9c Mon Sep 17 00:00:00 2001 From: meiyi Date: Wed, 21 Nov 2018 18:04:25 +0800 Subject: [PATCH] HBASE-21300 Fix the wrong reference file path when restoring snapshots for tables with MOB columns --- .../master/procedure/CloneSnapshotProcedure.java | 25 +++++++- .../java/org/apache/hadoop/hbase/mob/MobUtils.java | 14 ++++- .../hbase/snapshot/RestoreSnapshotHelper.java | 2 +- .../snapshot/TestMobRestoreSnapshotHelper.java | 22 +++++++ .../hbase/snapshot/TestRestoreSnapshotHelper.java | 72 ++++++++++++++++++++++ 5 files changed, 132 insertions(+), 3 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CloneSnapshotProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CloneSnapshotProcedure.java index 9ba3485..651e995 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CloneSnapshotProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CloneSnapshotProcedure.java @@ -42,6 +42,8 @@ import org.apache.hadoop.hbase.master.MetricsSnapshot; import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.master.assignment.AssignmentManager; import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure.CreateHdfsRegions; +import org.apache.hadoop.hbase.mob.MobConstants; +import org.apache.hadoop.hbase.mob.MobUtils; import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.monitoring.TaskMonitor; import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; @@ -470,10 +472,31 @@ public class CloneSnapshotProcedure // 3. Move Table temp directory to the hbase root location CreateTableProcedure.moveTempDirectoryToHBaseRoot(env, tableDescriptor, tempTableDir); - + // Move Table temp mob directory to the hbase root location + Path tempMobTableDir = FSUtils.getTableDir(new Path(tempdir, MobConstants.MOB_DIR_NAME), + tableDescriptor.getTableName()); + moveTempMobDirectoryToHBaseRoot(env, tableDescriptor, tempMobTableDir); return newRegions; } + private static void moveTempMobDirectoryToHBaseRoot(final MasterProcedureEnv env, + final TableDescriptor tableDescriptor, final Path tempMobTableDir) throws IOException { + final MasterFileSystem mfs = env.getMasterServices().getMasterFileSystem(); + FileSystem fs = mfs.getFileSystem(); + boolean mobEnabled = MobUtils.hasMobColumns(tableDescriptor); + if (mobEnabled) { + final Path tableMobDir = FSUtils.getTableDir( + new Path(mfs.getRootDir(), MobConstants.MOB_DIR_NAME), tableDescriptor.getTableName()); + if (!fs.delete(tableMobDir, true) && fs.exists(tableMobDir)) { + throw new IOException("Couldn't delete " + tableMobDir); + } + if (!fs.rename(tempMobTableDir, tableMobDir)) { + throw new IOException( + "Unable to move table from temp=" + tempMobTableDir + " to hbase root=" + tableMobDir); + } + } + } + /** * Add regions to hbase:meta table. * @param env MasterProcedureEnv diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java index 9fa4e4c..141b68d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobUtils.java @@ -391,7 +391,19 @@ public final class MobUtils { * @return The region dir of the mob files. */ public static Path getMobRegionPath(Configuration conf, TableName tableName) { - Path tablePath = FSUtils.getTableDir(getMobHome(conf), tableName); + return getMobRegionPath(new Path(conf.get(HConstants.HBASE_DIR)), tableName); + } + + /** + * Gets the region dir of the mob files under the specified root dir. + * {rootDir}/mobdir/{namespace}/{tableName}/{regionEncodedName}. + * @param rootDir The root dir. + * @param tableName The current table name. + * @return The region dir of the mob files. + */ + public static Path getMobRegionPath(Path rootDir, TableName tableName) { + Path mobHome = new Path(rootDir, MobConstants.MOB_DIR_NAME); + Path tablePath = FSUtils.getTableDir(mobHome, tableName); RegionInfo regionInfo = getMobRegionInfo(tableName); return new Path(tablePath, regionInfo.getEncodedName()); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java index 6aa378c..0acfb1a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java @@ -622,7 +622,7 @@ public class RestoreSnapshotHelper { private void cloneHdfsMobRegion(final Map regionManifests, final RegionInfo region) throws IOException { // clone region info (change embedded tableName with the new one) - Path clonedRegionPath = MobUtils.getMobRegionPath(conf, tableDesc.getTableName()); + Path clonedRegionPath = MobUtils.getMobRegionPath(rootDir, tableDesc.getTableName()); cloneRegion(clonedRegionPath, region, regionManifests.get(region.getEncodedName())); } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java index df8eb68..3abce8f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java @@ -20,9 +20,16 @@ package org.apache.hadoop.hbase.snapshot; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.mob.MobConstants; import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils.SnapshotMock; import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.Bytes; import org.junit.ClassRule; import org.junit.experimental.categories.Category; import org.slf4j.Logger; @@ -49,4 +56,19 @@ public class TestMobRestoreSnapshotHelper extends TestRestoreSnapshotHelper { protected SnapshotMock createSnapshotMock() throws IOException { return new SnapshotMock(TEST_UTIL.getConfiguration(), fs, rootDir); } + + @Override + protected void createTableAndSnapshot(TableName tableName, String snapshotName) + throws IOException { + TableDescriptor td = + TableDescriptorBuilder + .newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder + .newBuilder(Bytes.toBytes("A")).setMobEnabled(true).setMobThreshold(1).build()) + .build(); + Table table = TEST_UTIL.createTable(td, null); + Put put = new Put(Bytes.toBytes("row")); + put.addColumn(Bytes.toBytes("A"), null, Bytes.toBytes("test-val")); + table.put(put); + TEST_UTIL.getAdmin().snapshot(snapshotName, tableName); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestRestoreSnapshotHelper.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestRestoreSnapshotHelper.java index 08c5088..6eb8b02 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestRestoreSnapshotHelper.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestRestoreSnapshotHelper.java @@ -24,22 +24,35 @@ import java.io.IOException; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.RemoteIterator; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher; import org.apache.hadoop.hbase.io.HFileLink; +import org.apache.hadoop.hbase.mob.MobConstants; import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.regionserver.StoreFileInfo; import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils.SnapshotMock; import org.apache.hadoop.hbase.testclassification.RegionServerTests; import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.CommonFSUtils; import org.apache.hadoop.hbase.util.FSTableDescriptors; import org.apache.hadoop.hbase.util.FSUtils; import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -72,6 +85,16 @@ public class TestRestoreSnapshotHelper { protected void setupConf(Configuration conf) { } + @BeforeClass + public static void setupCluster() throws Exception { + TEST_UTIL.startMiniCluster(); + } + + @AfterClass + public static void tearDownCluster() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + @Before public void setup() throws Exception { rootDir = TEST_UTIL.getDataTestDir("testRestore"); @@ -101,6 +124,55 @@ public class TestRestoreSnapshotHelper { restoreAndVerify("snapshot", "namespace1:testRestoreWithNamespace"); } + @Test + public void testNoHFileLinkInRootDir() throws IOException { + rootDir = TEST_UTIL.getDefaultRootDirPath(); + FSUtils.setRootDir(conf, rootDir); + fs = rootDir.getFileSystem(conf); + + TableName tableName = TableName.valueOf("testNoHFileLinkInRootDir"); + String snapshotName = tableName.getNameAsString() + "-snapshot"; + createTableAndSnapshot(tableName, snapshotName); + + Path restoreDir = new Path("/hbase/.tmp-restore"); + RestoreSnapshotHelper.copySnapshotForScanner(conf, fs, rootDir, restoreDir, snapshotName); + checkNoHFileLinkInTableDir(tableName); + } + + protected void createTableAndSnapshot(TableName tableName, String snapshotName) + throws IOException { + TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName) + .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("A")).build()) + .build(); + Table table = TEST_UTIL.createTable(td, null); + Put put = new Put(Bytes.toBytes("row")); + put.addColumn(Bytes.toBytes("A"), null, Bytes.toBytes("test-val")); + table.put(put); + TEST_UTIL.getAdmin().snapshot(snapshotName, tableName); + } + + private void checkNoHFileLinkInTableDir(TableName tableName) throws IOException { + Path[] tableDirs = new Path[] { CommonFSUtils.getTableDir(rootDir, tableName), + CommonFSUtils.getTableDir(new Path(rootDir, HConstants.HFILE_ARCHIVE_DIRECTORY), tableName), + CommonFSUtils.getTableDir(new Path(rootDir, MobConstants.MOB_DIR_NAME), tableName) }; + for (Path tableDir : tableDirs) { + Assert.assertFalse(hasHFileLink(tableDir)); + } + } + + private boolean hasHFileLink(Path tableDir) throws IOException { + if (fs.exists(tableDir)) { + RemoteIterator iterator = fs.listFiles(tableDir, true); + while (iterator.hasNext()) { + LocatedFileStatus fileStatus = iterator.next(); + if (fileStatus.isFile() && HFileLink.isHFileLink(fileStatus.getPath())) { + return true; + } + } + } + return false; + } + private void restoreAndVerify(final String snapshotName, final String tableName) throws IOException { // Test Rolling-Upgrade like Snapshot. // half machines writing using v1 and the others using v2 format. -- 2.7.4