diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/backup/RestoreDriver.java hbase-server/src/main/java/org/apache/hadoop/hbase/backup/RestoreDriver.java index 83c8297..7dcd0f1 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/backup/RestoreDriver.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/backup/RestoreDriver.java @@ -18,14 +18,20 @@ package org.apache.hadoop.hbase.backup; import java.io.IOException; +import java.util.List; import org.apache.commons.cli.CommandLine; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.backup.impl.BackupRestoreConstants; +import org.apache.hadoop.hbase.backup.impl.BackupSystemTable; import org.apache.hadoop.hbase.backup.util.BackupServerUtil; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.util.AbstractHBaseTool; import org.apache.hadoop.hbase.util.LogUtils; import org.apache.hadoop.util.ToolRunner; @@ -40,9 +46,10 @@ public class RestoreDriver extends AbstractHBaseTool { private static final String OPTION_OVERWRITE = "overwrite"; private static final String OPTION_CHECK = "check"; private static final String OPTION_AUTOMATIC = "automatic"; + private static final String OPTION_SET = "set"; private static final String USAGE = - "Usage: hbase restore [tableMapping] \n" + "Usage: hbase restore [-set set_name] [tableMapping] \n" + " [-overwrite] [-check] [-automatic]\n" + " backup_root_path The parent location where the backup images are stored\n" + " backup_id The id identifying the backup image\n" @@ -61,7 +68,8 @@ public class RestoreDriver extends AbstractHBaseTool { + " The restore dependencies can be checked by using \"-check\" " + "option,\n" + " or using \"hbase backup describe\" command. Without this option, " - + "only\n" + " this backup image is restored\n"; + + "only\n" + " this backup image is restored\n" + + " -set set_name Backup set to restore, mutulaly exclusive with table list ."; protected RestoreDriver() throws IOException @@ -76,6 +84,7 @@ public class RestoreDriver extends AbstractHBaseTool { addOptNoArg(OPTION_CHECK, "Check restore sequence and dependencies"); addOptNoArg(OPTION_AUTOMATIC, "Restore all dependencies"); addOptNoArg("debug", "Enable debug logging"); + addOptWithArg("set", "Backup set name"); // disable irrelevant loggers to avoid it mess up command output LogUtils.disableUselessLoggers(LOG); @@ -119,9 +128,27 @@ public class RestoreDriver extends AbstractHBaseTool { String backupRootDir = remainArgs[0]; String backupId = remainArgs[1]; - String tables = remainArgs[2]; - - String tableMapping = (remainArgs.length > 3) ? remainArgs[3] : null; + String tables = null; + String tableMapping = null; + // Check backup set + if (cmd.hasOption("set")) { + String setName = cmd.getOptionValue("set"); + try{ + tables = getTablesForSet(setName, conf); + } catch(IOException e){ + System.out.println("ERROR: "+ e.getMessage()); + return -1; + } + if (tables == null) { + System.out.println("ERROR: Backup set '" + setName + + "' is either empty or does not exist"); + return -1; + } + tableMapping = (remainArgs.length > 2) ? remainArgs[2] : null; + } else { + tables = remainArgs[2]; + tableMapping = (remainArgs.length > 3) ? remainArgs[3] : null; + } TableName[] sTableArray = BackupServerUtil.parseTableNames(tables); TableName[] tTableArray = BackupServerUtil.parseTableNames(tableMapping); @@ -144,6 +171,16 @@ public class RestoreDriver extends AbstractHBaseTool { return 0; } + private String getTablesForSet(String name, Configuration conf) + throws IOException { + try (final Connection conn = ConnectionFactory.createConnection(conf); + final BackupSystemTable table = new BackupSystemTable(conn)) { + List tables = table.describeBackupSet(name); + if (tables == null) return null; + return StringUtils.join(tables, BackupRestoreConstants.TABLENAME_DELIMITER_IN_COMMAND); + } + } + @Override protected void addOptions() { } diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSet.java hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSet.java index a4c0fa1..a8fa7de 100644 --- hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSet.java +++ hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSet.java @@ -27,6 +27,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.backup.impl.BackupSystemTable; +import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.util.ToolRunner; import org.junit.Test; @@ -45,7 +46,7 @@ public class TestFullBackupSet extends TestBackupBase { @Test public void testFullBackupSetExist() throws Exception { - LOG.info("TFBSE test full backup, backup set exists"); + LOG.info("Test full backup, backup set exists"); //Create set try (BackupSystemTable table = new BackupSystemTable(TEST_UTIL.getConnection())) { @@ -65,7 +66,24 @@ public class TestFullBackupSet extends TestBackupBase { assertTrue(backups.size() == 1); String backupId = backups.get(0).getBackupId(); assertTrue(checkSucceeded(backupId)); - LOG.info("TFBSE backup complete"); + + LOG.info("backup complete"); + + // Restore from set into other table + args = new String[]{BACKUP_ROOT_DIR, backupId, + "-set", name, table1_restore.getNameAsString(), "-overwrite" }; + // Run backup + ret = ToolRunner.run(conf1, new RestoreDriver(), args); + assertTrue(ret == 0); + HBaseAdmin hba = TEST_UTIL.getHBaseAdmin(); + assertTrue(hba.tableExists(table1_restore)); + // Verify number of rows in both tables + assertEquals(TEST_UTIL.countRows(table1), TEST_UTIL.countRows(table1_restore)); + TEST_UTIL.deleteTable(table1_restore); + LOG.info("restore into other table is complete"); + hba.close(); + + } } diff --git hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSetRestoreSet.java hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSetRestoreSet.java new file mode 100644 index 0000000..a37b415 --- /dev/null +++ hbase-server/src/test/java/org/apache/hadoop/hbase/backup/TestFullBackupSetRestoreSet.java @@ -0,0 +1,130 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.backup; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.backup.impl.BackupSystemTable; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.apache.hadoop.util.ToolRunner; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(LargeTests.class) +public class TestFullBackupSetRestoreSet extends TestBackupBase { + + private static final Log LOG = LogFactory.getLog(TestFullBackupSetRestoreSet.class); + + @Test + public void testFullRestoreSetToOtherTable() throws Exception { + + LOG.info("Test full restore set"); + + //Create set + try (BackupSystemTable table = new BackupSystemTable(TEST_UTIL.getConnection())) { + String name = "name"; + table.addToBackupSet(name, new String[] { table1.getNameAsString() }); + List names = table.describeBackupSet(name); + + assertNotNull(names); + assertTrue(names.size() == 1); + assertTrue(names.get(0).equals(table1)); + + String[] args = new String[] { "create", "full", BACKUP_ROOT_DIR, "-set", name }; + // Run backup + int ret = ToolRunner.run(conf1, new BackupDriver(), args); + assertTrue(ret == 0); + ArrayList backups = table.getBackupHistory(); + assertTrue(backups.size() == 1); + String backupId = backups.get(0).getBackupId(); + assertTrue(checkSucceeded(backupId)); + + LOG.info("backup complete"); + + // Restore from set into other table + args = new String[]{BACKUP_ROOT_DIR, backupId, + "-set", name, table1_restore.getNameAsString(), "-overwrite" }; + // Run backup + ret = ToolRunner.run(conf1, new RestoreDriver(), args); + assertTrue(ret == 0); + HBaseAdmin hba = TEST_UTIL.getHBaseAdmin(); + assertTrue(hba.tableExists(table1_restore)); + // Verify number of rows in both tables + assertEquals(TEST_UTIL.countRows(table1), TEST_UTIL.countRows(table1_restore)); + TEST_UTIL.deleteTable(table1_restore); + LOG.info("restore into other table is complete"); + hba.close(); + + + } + + } + + public void testFullRestoreSetToSameTable() throws Exception { + + LOG.info("Test full restore set to same table"); + + //Create set + try (BackupSystemTable table = new BackupSystemTable(TEST_UTIL.getConnection())) { + String name = "name1"; + table.addToBackupSet(name, new String[] { table1.getNameAsString() }); + List names = table.describeBackupSet(name); + + assertNotNull(names); + assertTrue(names.size() == 1); + assertTrue(names.get(0).equals(table1)); + + String[] args = new String[] { "create", "full", BACKUP_ROOT_DIR, "-set", name }; + // Run backup + int ret = ToolRunner.run(conf1, new BackupDriver(), args); + assertTrue(ret == 0); + ArrayList backups = table.getBackupHistory(); + assertTrue(backups.size() == 1); + String backupId = backups.get(0).getBackupId(); + assertTrue(checkSucceeded(backupId)); + + LOG.info("backup complete"); + int count = TEST_UTIL.countRows(table1); + TEST_UTIL.deleteTable(table1); + + // Restore from set into other table + args = new String[]{BACKUP_ROOT_DIR, backupId, + "-set", name, "-overwrite" }; + // Run backup + ret = ToolRunner.run(conf1, new RestoreDriver(), args); + assertTrue(ret == 0); + HBaseAdmin hba = TEST_UTIL.getHBaseAdmin(); + assertTrue(hba.tableExists(table1)); + // Verify number of rows in both tables + assertEquals(count, TEST_UTIL.countRows(table1)); + LOG.info("restore into same table is complete"); + hba.close(); + + } + + } + +} \ No newline at end of file