Skip to content

Commit f388a5c

Browse files
author
Jarryd Lee
committed
HBASE-27541 Add support for defining restore hfile output path
Co-authored-by: Bryan Beaudreault <bbeaudreault@hubspot.com> Extract tmp restore output dir
1 parent 2a7c69d commit f388a5c

File tree

10 files changed

+125
-30
lines changed

10 files changed

+125
-30
lines changed

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/RestoreJob.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ public interface RestoreJob extends Configurable {
3434
* Run restore operation
3535
* @param dirPaths path array of WAL log directories
3636
* @param fromTables from tables
37+
* @param restoreRootDir output file system
3738
* @param toTables to tables
3839
* @param fullBackupRestore full backup restore
3940
* @throws IOException if running the job fails
4041
*/
41-
void run(Path[] dirPaths, TableName[] fromTables, TableName[] toTables, boolean fullBackupRestore)
42-
throws IOException;
42+
void run(Path[] dirPaths, TableName[] fromTables, Path restoreRootDir, TableName[] toTables,
43+
boolean fullBackupRestore) throws IOException;
4344
}

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/RestoreRequest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public Builder withBackupRootDir(String backupRootDir) {
3737
return this;
3838
}
3939

40+
public Builder withRestoreRootDir(String restoreRootDir) {
41+
request.setRestoreRootDir(restoreRootDir);
42+
return this;
43+
}
44+
4045
public Builder withBackupId(String backupId) {
4146
request.setBackupId(backupId);
4247
return this;
@@ -68,6 +73,7 @@ public RestoreRequest build() {
6873
}
6974

7075
private String backupRootDir;
76+
private String restoreRootDir;
7177
private String backupId;
7278
private boolean check = false;
7379
private TableName[] fromTables;
@@ -86,6 +92,15 @@ private RestoreRequest setBackupRootDir(String backupRootDir) {
8692
return this;
8793
}
8894

95+
public String getRestoreRootDir() {
96+
return restoreRootDir;
97+
}
98+
99+
private RestoreRequest setRestoreRootDir(String restoreRootDir) {
100+
this.restoreRootDir = restoreRootDir;
101+
return this;
102+
}
103+
89104
public String getBackupId() {
90105
return backupId;
91106
}

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/impl/RestoreTablesClient.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.hadoop.hbase.backup.HBackupFileSystem;
3636
import org.apache.hadoop.hbase.backup.RestoreRequest;
3737
import org.apache.hadoop.hbase.backup.impl.BackupManifest.BackupImage;
38+
import org.apache.hadoop.hbase.backup.util.BackupUtils;
3839
import org.apache.hadoop.hbase.backup.util.RestoreTool;
3940
import org.apache.hadoop.hbase.client.Admin;
4041
import org.apache.hadoop.hbase.client.Connection;
@@ -55,11 +56,12 @@ public class RestoreTablesClient {
5556
private String backupId;
5657
private TableName[] sTableArray;
5758
private TableName[] tTableArray;
58-
private String targetRootDir;
59+
private String backupRootDir;
60+
private Path restoreRootDir;
5961
private boolean isOverwrite;
6062

61-
public RestoreTablesClient(Connection conn, RestoreRequest request) {
62-
this.targetRootDir = request.getBackupRootDir();
63+
public RestoreTablesClient(Connection conn, RestoreRequest request) throws IOException {
64+
this.backupRootDir = request.getBackupRootDir();
6365
this.backupId = request.getBackupId();
6466
this.sTableArray = request.getFromTables();
6567
this.tTableArray = request.getToTables();
@@ -69,6 +71,12 @@ public RestoreTablesClient(Connection conn, RestoreRequest request) {
6971
this.isOverwrite = request.isOverwrite();
7072
this.conn = conn;
7173
this.conf = conn.getConfiguration();
74+
if (request.getRestoreRootDir() != null) {
75+
restoreRootDir = new Path(request.getRestoreRootDir());
76+
} else {
77+
FileSystem fs = FileSystem.get(conf);
78+
this.restoreRootDir = BackupUtils.getTmpRestoreOutputDir(fs, conf);
79+
}
7280
}
7381

7482
/**
@@ -131,7 +139,7 @@ private void restoreImages(BackupImage[] images, TableName sTable, TableName tTa
131139
String rootDir = image.getRootDir();
132140
String backupId = image.getBackupId();
133141
Path backupRoot = new Path(rootDir);
134-
RestoreTool restoreTool = new RestoreTool(conf, backupRoot, backupId);
142+
RestoreTool restoreTool = new RestoreTool(conf, backupRoot, restoreRootDir, backupId);
135143
Path tableBackupPath = HBackupFileSystem.getTableBackupPath(sTable, backupRoot, backupId);
136144
String lastIncrBackupId = images.length == 1 ? null : images[images.length - 1].getBackupId();
137145
// We need hFS only for full restore (see the code)
@@ -249,7 +257,7 @@ public void execute() throws IOException {
249257
// case RESTORE_IMAGES:
250258
HashMap<TableName, BackupManifest> backupManifestMap = new HashMap<>();
251259
// check and load backup image manifest for the tables
252-
Path rootPath = new Path(targetRootDir);
260+
Path rootPath = new Path(backupRootDir);
253261
HBackupFileSystem.checkImageManifestExist(backupManifestMap, sTableArray, conf, rootPath,
254262
backupId);
255263

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/mapreduce/MapReduceBackupMergeJob.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ public void run(String[] backupIds) throws IOException {
120120
Path[] dirPaths = findInputDirectories(fs, backupRoot, tableNames[i], backupIds);
121121
String dirs = StringUtils.join(dirPaths, ",");
122122

123-
Path bulkOutputPath = BackupUtils.getBulkOutputDir(
123+
Path tmpPath = BackupUtils.getTmpRestoreOutputDir(fs, conf);
124+
Path bulkOutputPath = BackupUtils.getBulkOutputDir(tmpPath,
124125
BackupUtils.getFileNameCompatibleString(tableNames[i]), getConf(), false);
125126
// Delete content if exists
126127
if (fs.exists(bulkOutputPath)) {

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/mapreduce/MapReduceRestoreJob.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public MapReduceRestoreJob() {
5050
}
5151

5252
@Override
53-
public void run(Path[] dirPaths, TableName[] tableNames, TableName[] newTableNames,
54-
boolean fullBackupRestore) throws IOException {
53+
public void run(Path[] dirPaths, TableName[] tableNames, Path restoreRootDir,
54+
TableName[] newTableNames, boolean fullBackupRestore) throws IOException {
5555
String bulkOutputConfKey;
5656

5757
player = new MapReduceHFileSplitterJob();
@@ -70,9 +70,8 @@ public void run(Path[] dirPaths, TableName[] tableNames, TableName[] newTableNam
7070

7171
for (int i = 0; i < tableNames.length; i++) {
7272
LOG.info("Restore " + tableNames[i] + " into " + newTableNames[i]);
73-
74-
Path bulkOutputPath = BackupUtils
75-
.getBulkOutputDir(BackupUtils.getFileNameCompatibleString(newTableNames[i]), getConf());
73+
Path bulkOutputPath = BackupUtils.getBulkOutputDir(restoreRootDir,
74+
BackupUtils.getFileNameCompatibleString(newTableNames[i]), getConf());
7675
Configuration conf = getConf();
7776
conf.set(bulkOutputConfKey, bulkOutputPath.toString());
7877
String[] playerArgs = { dirs,

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/BackupUtils.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -690,21 +690,32 @@ public static boolean validate(HashMap<TableName, BackupManifest> backupManifest
690690
return isValid;
691691
}
692692

693-
public static Path getBulkOutputDir(String tableName, Configuration conf, boolean deleteOnExit)
694-
throws IOException {
695-
FileSystem fs = FileSystem.get(conf);
696-
String tmp =
697-
conf.get(HConstants.TEMPORARY_FS_DIRECTORY_KEY, fs.getHomeDirectory() + "/hbase-staging");
698-
Path path = new Path(tmp + Path.SEPARATOR + "bulk_output-" + tableName + "-"
699-
+ EnvironmentEdgeManager.currentTime());
693+
public static Path getBulkOutputDir(Path restoreRootDir, String tableName, Configuration conf,
694+
boolean deleteOnExit) throws IOException {
695+
FileSystem fs = restoreRootDir.getFileSystem(conf);
696+
Path path = new Path(restoreRootDir,
697+
"bulk_output-" + tableName + "-" + EnvironmentEdgeManager.currentTime());
700698
if (deleteOnExit) {
701699
fs.deleteOnExit(path);
702700
}
703701
return path;
704702
}
705703

706-
public static Path getBulkOutputDir(String tableName, Configuration conf) throws IOException {
707-
return getBulkOutputDir(tableName, conf, true);
704+
/**
705+
* Build temporary output path
706+
* @param fs filesystem for default output dir
707+
* @param conf configuration
708+
* @return output path
709+
*/
710+
public static Path getTmpRestoreOutputDir(FileSystem fs, Configuration conf) {
711+
String tmp =
712+
conf.get(HConstants.TEMPORARY_FS_DIRECTORY_KEY, fs.getHomeDirectory() + "/hbase-staging");
713+
return new Path(tmp);
714+
}
715+
716+
public static Path getBulkOutputDir(Path restoreRootDir, String tableName, Configuration conf)
717+
throws IOException {
718+
return getBulkOutputDir(restoreRootDir, tableName, conf, true);
708719
}
709720

710721
public static String getFileNameCompatibleString(TableName table) {

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/util/RestoreTool.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,20 @@ public class RestoreTool {
6767
private final String[] ignoreDirs = { HConstants.RECOVERED_EDITS_DIR };
6868
protected Configuration conf;
6969
protected Path backupRootPath;
70+
protected Path restoreRootDir;
7071
protected String backupId;
7172
protected FileSystem fs;
7273

7374
// store table name and snapshot dir mapping
7475
private final HashMap<TableName, Path> snapshotMap = new HashMap<>();
7576

76-
public RestoreTool(Configuration conf, final Path backupRootPath, final String backupId)
77-
throws IOException {
77+
public RestoreTool(Configuration conf, final Path backupRootPath, final Path restoreRootDir,
78+
final String backupId) throws IOException {
7879
this.conf = conf;
7980
this.backupRootPath = backupRootPath;
8081
this.backupId = backupId;
8182
this.fs = backupRootPath.getFileSystem(conf);
83+
this.restoreRootDir = restoreRootDir;
8284
}
8385

8486
/**
@@ -200,7 +202,7 @@ public void incrementalRestoreTable(Connection conn, Path tableBackupPath, Path[
200202
}
201203
RestoreJob restoreService = BackupRestoreFactory.getRestoreJob(conf);
202204

203-
restoreService.run(logDirs, tableNames, newTableNames, false);
205+
restoreService.run(logDirs, tableNames, restoreRootDir, newTableNames, false);
204206
}
205207
}
206208

@@ -350,8 +352,8 @@ private void createAndRestoreTable(Connection conn, TableName tableName, TableNa
350352
RestoreJob restoreService = BackupRestoreFactory.getRestoreJob(conf);
351353
Path[] paths = new Path[regionPathList.size()];
352354
regionPathList.toArray(paths);
353-
restoreService.run(paths, new TableName[] { tableName }, new TableName[] { newTableName },
354-
true);
355+
restoreService.run(paths, new TableName[] { tableName }, restoreRootDir,
356+
new TableName[] { newTableName }, true);
355357

356358
} catch (Exception e) {
357359
LOG.error(e.toString(), e);

hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestBackupUtils.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ public Path run() {
7373
Path bulkOutputDir = ugi.doAs(new PrivilegedAction<Path>() {
7474
@Override
7575
public Path run() {
76-
try {
77-
return BackupUtils.getBulkOutputDir("test", conf, false);
76+
try (FileSystem fs = FileSystem.get(conf)) {
77+
Path tmpPath = BackupUtils.getTmpRestoreOutputDir(fs, conf);
78+
return BackupUtils.getBulkOutputDir(tmpPath, "test", conf, false);
7879
} catch (IOException ioe) {
7980
LOG.error("Failed to get bulk output dir path", ioe);
8081
}

hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestIncrementalBackupMergeWithFailures.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ public void run(String[] backupIds) throws IOException {
130130
// Find input directories for table
131131
Path[] dirPaths = findInputDirectories(fs, backupRoot, tableNames[i], backupIds);
132132
String dirs = StringUtils.join(dirPaths, ",");
133-
Path bulkOutputPath = BackupUtils.getBulkOutputDir(
133+
Path tmpPath = BackupUtils.getTmpRestoreOutputDir(fs, conf);
134+
Path bulkOutputPath = BackupUtils.getBulkOutputDir(tmpPath,
134135
BackupUtils.getFileNameCompatibleString(tableNames[i]), getConf(), false);
135136
// Delete content if exists
136137
if (fs.exists(bulkOutputPath)) {

hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestRemoteRestore.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@
1717
*/
1818
package org.apache.hadoop.hbase.backup;
1919

20+
import static org.junit.Assert.assertFalse;
2021
import static org.junit.Assert.assertTrue;
2122

23+
import org.apache.hadoop.conf.Configuration;
24+
import org.apache.hadoop.fs.FileSystem;
25+
import org.apache.hadoop.fs.Path;
2226
import org.apache.hadoop.hbase.HBaseClassTestRule;
2327
import org.apache.hadoop.hbase.HBaseTestingUtil;
28+
import org.apache.hadoop.hbase.HConstants;
2429
import org.apache.hadoop.hbase.TableName;
30+
import org.apache.hadoop.hbase.backup.impl.BackupAdminImpl;
31+
import org.apache.hadoop.hbase.backup.mapreduce.MapReduceHFileSplitterJob;
2532
import org.apache.hadoop.hbase.backup.util.BackupUtils;
2633
import org.apache.hadoop.hbase.client.Admin;
34+
import org.apache.hadoop.hbase.client.ConnectionFactory;
2735
import org.apache.hadoop.hbase.testclassification.LargeTests;
2836
import org.junit.BeforeClass;
2937
import org.junit.ClassRule;
@@ -49,6 +57,7 @@ public class TestRemoteRestore extends TestBackupBase {
4957
public static void setUp() throws Exception {
5058
TEST_UTIL = new HBaseTestingUtil();
5159
conf1 = TEST_UTIL.getConfiguration();
60+
conf1.set(HConstants.CLUSTER_DISTRIBUTED, "true");
5261
useSecondCluster = true;
5362
setUpHelper();
5463
}
@@ -72,4 +81,51 @@ public void testFullRestoreRemote() throws Exception {
7281
TEST_UTIL.deleteTable(table1_restore);
7382
hba.close();
7483
}
84+
85+
/**
86+
* Verify that restore jobs can be run on a standalone mapreduce cluster. Ensures hfiles output
87+
* via {@link MapReduceHFileSplitterJob} exist on correct filesystem.
88+
* @throws Exception if doing the backup or an operation on the tables fails
89+
*/
90+
@Test
91+
public void testFullRestoreRemoteWithAlternateRestoreOutputDir() throws Exception {
92+
LOG.info("test remote full backup on a single table with alternate restore output dir");
93+
String backupId =
94+
backupTables(BackupType.FULL, toList(table1.getNameAsString()), BACKUP_REMOTE_ROOT_DIR);
95+
LOG.info("backup complete");
96+
TableName[] tableset = new TableName[] { table1 };
97+
TableName[] tablemap = new TableName[] { table1_restore };
98+
99+
HBaseTestingUtil mrTestUtil = new HBaseTestingUtil();
100+
mrTestUtil.setZkCluster(TEST_UTIL.getZkCluster());
101+
mrTestUtil.startMiniDFSCluster(3);
102+
mrTestUtil.startMiniMapReduceCluster();
103+
104+
Configuration testUtilConf = TEST_UTIL.getConnection().getConfiguration();
105+
Configuration conf = new Configuration(mrTestUtil.getConfiguration());
106+
conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT,
107+
testUtilConf.get(HConstants.ZOOKEEPER_ZNODE_PARENT));
108+
conf.set(HConstants.MASTER_ADDRS_KEY, testUtilConf.get(HConstants.MASTER_ADDRS_KEY));
109+
110+
new BackupAdminImpl(ConnectionFactory.createConnection(conf))
111+
.restore(new RestoreRequest.Builder().withBackupRootDir(BACKUP_REMOTE_ROOT_DIR)
112+
.withRestoreRootDir(BACKUP_ROOT_DIR).withBackupId(backupId).withCheck(false)
113+
.withFromTables(tableset).withToTables(tablemap).withOvewrite(false).build());
114+
115+
Path hfileOutputPath = new Path(
116+
new Path(conf.get(MapReduceHFileSplitterJob.BULK_OUTPUT_CONF_KEY)).toUri().getPath());
117+
118+
// files exist on hbase cluster
119+
FileSystem fileSystem = FileSystem.get(TEST_UTIL.getConfiguration());
120+
assertTrue(fileSystem.exists(hfileOutputPath));
121+
122+
// files don't exist on MR cluster
123+
fileSystem = FileSystem.get(conf);
124+
assertFalse(fileSystem.exists(hfileOutputPath));
125+
126+
Admin hba = TEST_UTIL.getAdmin();
127+
assertTrue(hba.tableExists(table1_restore));
128+
TEST_UTIL.deleteTable(table1_restore);
129+
hba.close();
130+
}
75131
}

0 commit comments

Comments
 (0)