Skip to content

Commit 0619d4a

Browse files
committed
HBASE-29445 Add Option to Specify Custom Backup Location in PITR (apache#7153)
Signed-off-by: Tak Lon (Stephen) Wu <[email protected]>
1 parent 5bcab7c commit 0619d4a

File tree

10 files changed

+962
-416
lines changed

10 files changed

+962
-416
lines changed

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

Lines changed: 403 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 17 additions & 331 deletions
Large diffs are not rendered by default.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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.backup.impl;
19+
20+
import java.util.List;
21+
import org.apache.hadoop.hbase.TableName;
22+
import org.apache.hadoop.hbase.backup.impl.BackupManifest.BackupImage;
23+
import org.apache.yetus.audience.InterfaceAudience;
24+
25+
/**
26+
* Adapter that wraps a {@link BackupImage} to expose it as {@link PitrBackupMetadata}.
27+
*/
28+
@InterfaceAudience.Private
29+
public class BackupImageAdapter implements PitrBackupMetadata {
30+
private final BackupImage image;
31+
32+
public BackupImageAdapter(BackupImage image) {
33+
this.image = image;
34+
}
35+
36+
@Override
37+
public List<TableName> getTableNames() {
38+
return image.getTableNames();
39+
}
40+
41+
@Override
42+
public long getStartTs() {
43+
return image.getStartTs();
44+
}
45+
46+
@Override
47+
public long getCompleteTs() {
48+
return image.getCompleteTs();
49+
}
50+
51+
@Override
52+
public String getBackupId() {
53+
return image.getBackupId();
54+
}
55+
56+
@Override
57+
public String getRootDir() {
58+
return image.getRootDir();
59+
}
60+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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.backup.impl;
19+
20+
import java.util.List;
21+
import org.apache.hadoop.hbase.TableName;
22+
import org.apache.hadoop.hbase.backup.BackupInfo;
23+
import org.apache.yetus.audience.InterfaceAudience;
24+
25+
/**
26+
* Adapter that wraps a {@link BackupInfo} to expose it as {@link PitrBackupMetadata}.
27+
*/
28+
@InterfaceAudience.Private
29+
public class BackupInfoAdapter implements PitrBackupMetadata {
30+
private final BackupInfo info;
31+
32+
public BackupInfoAdapter(BackupInfo info) {
33+
this.info = info;
34+
}
35+
36+
@Override
37+
public List<TableName> getTableNames() {
38+
return info.getTableNames();
39+
}
40+
41+
@Override
42+
public long getStartTs() {
43+
return info.getStartTs();
44+
}
45+
46+
@Override
47+
public long getCompleteTs() {
48+
return info.getCompleteTs();
49+
}
50+
51+
@Override
52+
public String getBackupId() {
53+
return info.getBackupId();
54+
}
55+
56+
@Override
57+
public String getRootDir() {
58+
return info.getBackupRootDir();
59+
}
60+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.backup.impl;
19+
20+
import java.io.IOException;
21+
import java.util.List;
22+
import java.util.stream.Collectors;
23+
import org.apache.hadoop.fs.Path;
24+
import org.apache.hadoop.hbase.backup.HBackupFileSystem;
25+
import org.apache.hadoop.hbase.backup.PointInTimeRestoreRequest;
26+
import org.apache.hadoop.hbase.client.Connection;
27+
import org.apache.yetus.audience.InterfaceAudience;
28+
29+
/**
30+
* PITR restore handler that retrieves backup metadata from a custom backup root directory.
31+
* <p>
32+
* This implementation is used when the PITR request specifies a custom backup location via
33+
* {@code backupRootDir}.
34+
*/
35+
@InterfaceAudience.Private
36+
public class CustomBackupLocationPitrRestoreHandler extends AbstractPitrRestoreHandler {
37+
38+
public CustomBackupLocationPitrRestoreHandler(Connection conn,
39+
PointInTimeRestoreRequest request) {
40+
super(conn, request);
41+
}
42+
43+
/**
44+
* Retrieves completed backup entries from the given custom backup root directory and converts
45+
* them into {@link PitrBackupMetadata} using {@link BackupImageAdapter}.
46+
* @param request the PITR request
47+
* @return list of completed backup metadata entries from the custom location
48+
* @throws IOException if reading from the custom backup directory fails
49+
*/
50+
@Override
51+
protected List<PitrBackupMetadata> getBackupMetadata(PointInTimeRestoreRequest request)
52+
throws IOException {
53+
return HBackupFileSystem
54+
.getAllBackupImages(conn.getConfiguration(), new Path(request.getBackupRootDir())).stream()
55+
.map(BackupImageAdapter::new).collect(Collectors.toList());
56+
}
57+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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.backup.impl;
19+
20+
import java.io.IOException;
21+
import java.util.List;
22+
import java.util.stream.Collectors;
23+
import org.apache.hadoop.hbase.backup.BackupInfo;
24+
import org.apache.hadoop.hbase.backup.PointInTimeRestoreRequest;
25+
import org.apache.hadoop.hbase.client.Connection;
26+
import org.apache.yetus.audience.InterfaceAudience;
27+
28+
/**
29+
* Default PITR restore handler that retrieves backup metadata from the system table.
30+
* <p>
31+
* This implementation is used when no custom backup root directory is specified in the request.
32+
*/
33+
@InterfaceAudience.Private
34+
public class DefaultPitrRestoreHandler extends AbstractPitrRestoreHandler {
35+
36+
public DefaultPitrRestoreHandler(Connection conn, PointInTimeRestoreRequest request) {
37+
super(conn, request);
38+
}
39+
40+
/**
41+
* Retrieves completed backup entries from the BackupSystemTable and converts them into
42+
* {@link PitrBackupMetadata} using {@link BackupInfoAdapter}.
43+
* @param request the PITR request
44+
* @return list of completed backup metadata entries
45+
* @throws IOException if reading from the backup system table fails
46+
*/
47+
@Override
48+
protected List<PitrBackupMetadata> getBackupMetadata(PointInTimeRestoreRequest request)
49+
throws IOException {
50+
try (BackupSystemTable table = new BackupSystemTable(conn)) {
51+
return table.getBackupInfos(BackupInfo.BackupState.COMPLETE).stream()
52+
.map(BackupInfoAdapter::new).collect(Collectors.toList());
53+
}
54+
}
55+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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.backup.impl;
19+
20+
import java.util.List;
21+
import org.apache.hadoop.hbase.TableName;
22+
import org.apache.hadoop.hbase.backup.BackupInfo;
23+
import org.apache.hadoop.hbase.backup.impl.BackupManifest.BackupImage;
24+
import org.apache.yetus.audience.InterfaceAudience;
25+
26+
/**
27+
* A unified abstraction over backup metadata used during Point-In-Time Restore (PITR).
28+
* <p>
29+
* This interface allows the PITR algorithm to operate uniformly over different types of backup
30+
* metadata sources, such as {@link BackupInfo} (system table) and {@link BackupImage} (custom
31+
* backup location), without knowing their specific implementations.
32+
*/
33+
@InterfaceAudience.Private
34+
public interface PitrBackupMetadata {
35+
36+
/** Returns List of table names included in the backup */
37+
List<TableName> getTableNames();
38+
39+
/** Returns Start timestamp of the backup */
40+
long getStartTs();
41+
42+
/** Returns Completion timestamp of the backup */
43+
long getCompleteTs();
44+
45+
/** Returns Unique identifier for the backup */
46+
String getBackupId();
47+
48+
/** Returns Root directory where the backup is stored */
49+
String getRootDir();
50+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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.backup;
19+
20+
import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_ENABLE_CONTINUOUS_BACKUP;
21+
import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_PITR_BACKUP_PATH;
22+
import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE;
23+
import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TABLE_MAPPING;
24+
import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_TO_DATETIME;
25+
26+
import java.io.IOException;
27+
import java.util.ArrayList;
28+
import java.util.Arrays;
29+
import java.util.List;
30+
import java.util.stream.Collectors;
31+
import org.apache.hadoop.hbase.HBaseTestingUtil;
32+
import org.apache.hadoop.hbase.TableName;
33+
import org.apache.hadoop.hbase.client.Table;
34+
import org.apache.yetus.audience.InterfaceAudience;
35+
import org.slf4j.Logger;
36+
import org.slf4j.LoggerFactory;
37+
38+
@InterfaceAudience.Private
39+
public final class PITRTestUtil {
40+
private static final Logger LOG = LoggerFactory.getLogger(PITRTestUtil.class);
41+
private static final int DEFAULT_WAIT_FOR_REPLICATION_MS = 30_000;
42+
43+
private PITRTestUtil() {
44+
// Utility class
45+
}
46+
47+
public static String[] buildPITRArgs(TableName[] sourceTables, TableName[] targetTables,
48+
long endTime, String backupRootDir) {
49+
String sourceTableNames =
50+
Arrays.stream(sourceTables).map(TableName::getNameAsString).collect(Collectors.joining(","));
51+
String targetTableNames =
52+
Arrays.stream(targetTables).map(TableName::getNameAsString).collect(Collectors.joining(","));
53+
54+
List<String> args = new ArrayList<>();
55+
args.add("-" + OPTION_TABLE);
56+
args.add(sourceTableNames);
57+
args.add("-" + OPTION_TABLE_MAPPING);
58+
args.add(targetTableNames);
59+
args.add("-" + OPTION_TO_DATETIME);
60+
args.add(String.valueOf(endTime));
61+
62+
if (backupRootDir != null) {
63+
args.add("-" + OPTION_PITR_BACKUP_PATH);
64+
args.add(backupRootDir);
65+
}
66+
67+
return args.toArray(new String[0]);
68+
}
69+
70+
public static String[] buildBackupArgs(String backupType, TableName[] tables,
71+
boolean continuousEnabled, String backupRootDir) {
72+
String tableNames =
73+
Arrays.stream(tables).map(TableName::getNameAsString).collect(Collectors.joining(","));
74+
75+
List<String> args = new ArrayList<>(
76+
Arrays.asList("create", backupType, backupRootDir, "-" + OPTION_TABLE, tableNames));
77+
78+
if (continuousEnabled) {
79+
args.add("-" + OPTION_ENABLE_CONTINUOUS_BACKUP);
80+
}
81+
82+
return args.toArray(new String[0]);
83+
}
84+
85+
public static void loadRandomData(HBaseTestingUtil testUtil, TableName tableName, byte[] family,
86+
int totalRows) throws IOException {
87+
try (Table table = testUtil.getConnection().getTable(tableName)) {
88+
testUtil.loadRandomRows(table, family, 32, totalRows);
89+
}
90+
}
91+
92+
public static void waitForReplication() {
93+
try {
94+
LOG.info("Waiting for replication to complete for {} ms", DEFAULT_WAIT_FOR_REPLICATION_MS);
95+
Thread.sleep(DEFAULT_WAIT_FOR_REPLICATION_MS);
96+
} catch (InterruptedException e) {
97+
Thread.currentThread().interrupt();
98+
throw new RuntimeException("Interrupted while waiting for replication", e);
99+
}
100+
}
101+
102+
public static int getRowCount(HBaseTestingUtil testUtil, TableName tableName) throws IOException {
103+
try (Table table = testUtil.getConnection().getTable(tableName)) {
104+
return HBaseTestingUtil.countRows(table);
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)