Copilot commented on code in PR #7151:
URL: https://github.com/apache/hbase/pull/7151#discussion_r2202753067
##########
hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/impl/IncrementalTableBackupClient.java:
##########
@@ -370,13 +376,55 @@ protected void deleteBulkLoadDirectory() throws
IOException {
}
}
- protected void convertWALsToHFiles() throws IOException {
- // get incremental backup file list and prepare parameters for DistCp
- List<String> incrBackupFileList = backupInfo.getIncrBackupFileList();
+ protected Set<String> convertWALsToHFiles() throws IOException {
+ Set<String> backupFiles = new
HashSet<>(backupInfo.getIncrBackupFileList());
+ // filter missing files out (they have been copied by previous backups)
+ backupFiles = filterMissingFiles(backupFiles);
+ int attempt = 1;
+ int maxAttempts = conf.getInt(CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_KEY,
backupFiles.size());
Review Comment:
The default fallback for `maxAttempts` uses `backupFiles.size()` instead of
the declared `CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_DEFAULT`. Use the constant as
the default: `conf.getInt(..., CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_DEFAULT)`.
```suggestion
int maxAttempts = conf.getInt(CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_KEY,
CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_DEFAULT);
```
##########
hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestIncrementalBackup.java:
##########
@@ -500,6 +508,65 @@ public void TestIncBackupRestoreHandlesArchivedFiles()
throws Exception {
}
}
+ @Test
+ public void TestIncBackupHandlesArchivedWALFiles() throws Exception {
+ BackupAdminImpl admin = new BackupAdminImpl(TEST_UTIL.getConnection());
+ List<TableName> tables = Lists.newArrayList(table1);
+ insertIntoTable(TEST_UTIL.getConnection(), table1, famName, 1, 100);
+ String fullBackupId = takeFullBackup(tables, admin, true);
+ assertTrue(checkSucceeded(fullBackupId));
+
+ insertIntoTable(TEST_UTIL.getConnection(), table1, famName, 3, 100);
+ List<ServerAndWals> walsForFam = getWALsForFam(famName);
+
+ // Trigger a WAL roll to ensure WAL files are archived
+ List<String> backupFiles = new ArrayList<>();
+ Set<String> expectedWALs = Collections.synchronizedSet(new HashSet<>());
+ for (ServerAndWals serverAndWals : walsForFam) {
+ backupFiles.addAll(serverAndWals.walNames);
+ final CountDownLatch latch = new
CountDownLatch(serverAndWals.wals.size());
+ WALActionsListener listener = new WALActionsListener() {
+ @Override
+ public void postLogArchive(Path oldPath, Path newPath) throws
IOException {
+ // Make sure this is a WAL file that we are tracking
+ if (serverAndWals.contains(oldPath)) {
+ latch.countDown();
+ expectedWALs.add(newPath.toString());
+ }
+ }
+ };
+
+ serverAndWals.wals.forEach(wal ->
wal.registerWALActionsListener(listener));
+ TEST_UTIL.flush();
+ TEST_UTIL.getAdmin().rollWALWriter(serverAndWals.rs.getServerName());
+ latch.await();
Review Comment:
Calling `await()` without a timeout can hang the test indefinitely if the
listener never fires. Use `await(timeout, unit)` and fail the test on timeout.
```suggestion
if (!latch.await(60, java.util.concurrent.TimeUnit.SECONDS)) {
throw new AssertionError("Timeout waiting for WAL archival to
complete.");
}
```
##########
hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/impl/IncrementalTableBackupClient.java:
##########
@@ -370,13 +376,55 @@ protected void deleteBulkLoadDirectory() throws
IOException {
}
}
- protected void convertWALsToHFiles() throws IOException {
- // get incremental backup file list and prepare parameters for DistCp
- List<String> incrBackupFileList = backupInfo.getIncrBackupFileList();
+ protected Set<String> convertWALsToHFiles() throws IOException {
+ Set<String> backupFiles = new
HashSet<>(backupInfo.getIncrBackupFileList());
+ // filter missing files out (they have been copied by previous backups)
+ backupFiles = filterMissingFiles(backupFiles);
+ int attempt = 1;
+ int maxAttempts = conf.getInt(CONVERT_TO_WAL_TO_HFILES_ATTEMPTS_KEY,
backupFiles.size());
+
+ while (attempt <= maxAttempts) {
+ try {
+ LOG.info("Converting WALs to HFiles. Attempt={}/{}", attempt,
maxAttempts);
+ convertWALsToHFiles(backupFiles);
+ return backupFiles;
+ } catch (FileNotFoundException e) {
+ LOG.warn("Failed to convert WALs to HFiles", e);
+ // We need to deal with the possibility of the active WAL file being
rolled over
+ // as we're trying to copy it
+
+ Set<String> newBackupFiles = new HashSet<>(backupFiles.size());
+ for (String file : backupFiles) {
+ Path path = new Path(file);
+ if (!isActiveWalPath(path) || fs.exists(path)) {
+ newBackupFiles.add(file);
+ continue;
+ }
+
+ Path archive = AbstractFSWALProvider.findArchivedLog(path, conf);
+ if (archive == null) {
+ throw new IOException("Could not find archive for missing WAL file
" + path);
+ }
+
+ LOG.info("WAL file {} was archived during backup process, using
archive {}", path,
+ archive);
+ newBackupFiles.add(archive.toString());
+ }
+
+ if (newBackupFiles.equals(backupFiles)) {
+ throw e;
+ }
+
+ backupFiles = newBackupFiles;
+ ++attempt;
+ }
+ }
+ throw new IOException("Failed to convert WALs to HFiles after " + attempt
+ " attempts");
Review Comment:
The `attempt` variable has been incremented past `maxAttempts`, so the
message may report an off-by-one count. Consider using `maxAttempts` for
clarity.
```suggestion
throw new IOException("Failed to convert WALs to HFiles after " +
maxAttempts + " attempts");
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]