Skip to content

Commit 93e93bc

Browse files
committed
HBASE-29604 BackupHFileCleaner uses flawed time based check
Adds javadoc mentioning the concurrent usage and thread-safety need of FileCleanerDelegate#getDeletableFiles. Fixes a potential thread-safety issue in BackupHFileCleaner: this class tracks timestamps to block the deletion of recently loaded HFiles that might be needed for backup purposes. The timestamps were being registered from inside the concurrent method, which could result in recently added files getting deleted. Moved the timestamp registration to the postClean method, which is called only a single time per cleaner run, so recently loaded HFiles are in fact protected from deletion.
1 parent 82e36a2 commit 93e93bc

3 files changed

Lines changed: 16 additions & 8 deletions

File tree

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ public class BackupHFileCleaner extends BaseHFileCleanerDelegate implements Abor
5252
private boolean stopped = false;
5353
private boolean aborted = false;
5454
private Connection connection;
55-
// timestamp of most recent read from backup system table
56-
private long prevReadFromBackupTbl = 0;
57-
// timestamp of 2nd most recent read from backup system table
58-
private long secondPrevReadFromBackupTbl = 0;
55+
// timestamp of most recent completed cleaning run
56+
private volatile long previousCleaningCompletionTimestamp = 0;
57+
58+
@Override
59+
public void postClean() {
60+
previousCleaningCompletionTimestamp = EnvironmentEdgeManager.currentTime();
61+
}
5962

6063
@Override
6164
public Iterable<FileStatus> getDeletableFiles(Iterable<FileStatus> files) {
@@ -79,12 +82,9 @@ public Iterable<FileStatus> getDeletableFiles(Iterable<FileStatus> files) {
7982
return Collections.emptyList();
8083
}
8184

82-
secondPrevReadFromBackupTbl = prevReadFromBackupTbl;
83-
prevReadFromBackupTbl = EnvironmentEdgeManager.currentTime();
84-
8585
return Iterables.filter(files, file -> {
8686
// If the file is recent, be conservative and wait for one more scan of the bulk loads
87-
if (file.getModificationTime() > secondPrevReadFromBackupTbl) {
87+
if (file.getModificationTime() > previousCleaningCompletionTimestamp) {
8888
LOG.debug("Preventing deletion due to timestamp: {}", file.getPath().toString());
8989
return false;
9090
}

hbase-server/src/main/java/org/apache/hadoop/hbase/master/cleaner/BaseFileCleanerDelegate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ public void init(Map<String, Object> params) {
4444

4545
/**
4646
* Should the master delete the file or keep it?
47+
* <p>
48+
* This method can be called concurrently by multiple threads. Implementations must be thread
49+
* safe.
50+
* </p>
4751
* @param fStat file status of the file to check
4852
* @return <tt>true</tt> if the file is deletable, <tt>false</tt> if not
4953
*/

hbase-server/src/main/java/org/apache/hadoop/hbase/master/cleaner/FileCleanerDelegate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public interface FileCleanerDelegate extends Configurable, Stoppable {
3333

3434
/**
3535
* Determines which of the given files are safe to delete
36+
* <p>
37+
* This method can be called concurrently by multiple threads. Implementations must be thread
38+
* safe.
39+
* </p>
3640
* @param files files to check for deletion
3741
* @return files that are ok to delete according to this cleaner
3842
*/

0 commit comments

Comments
 (0)