Skip to content

Commit 76d56bc

Browse files
committed
HBASE-25899 Improve efficiency of SnapshotHFileCleaner (#3280)
Signed-off-by: Duo Zhang <zhangduo@apache.org>
1 parent 1c1acee commit 76d56bc

2 files changed

Lines changed: 27 additions & 23 deletions

File tree

hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotFileCache.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
import java.io.IOException;
2121
import java.util.Collection;
2222
import java.util.HashMap;
23-
import java.util.HashSet;
2423
import java.util.List;
2524
import java.util.Map;
26-
import java.util.Set;
2725
import java.util.Timer;
2826
import java.util.TimerTask;
2927
import java.util.concurrent.locks.Lock;
@@ -36,6 +34,8 @@
3634
import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException;
3735
import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
3836
import org.apache.hadoop.hbase.util.CommonFSUtils;
37+
import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
38+
import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet;
3939
import org.apache.yetus.audience.InterfaceAudience;
4040
import org.apache.yetus.audience.InterfaceStability;
4141
import org.slf4j.Logger;
@@ -91,12 +91,12 @@ Collection<String> filesUnderSnapshot(final FileSystem fs, final Path snapshotDi
9191
private final FileSystem fs, workingFs;
9292
private final SnapshotFileInspector fileInspector;
9393
private final Path snapshotDir, workingSnapshotDir;
94-
private final Set<String> cache = new HashSet<>();
94+
private volatile ImmutableSet<String> cache = ImmutableSet.of();
9595
/**
9696
* This is a helper map of information about the snapshot directories so we don't need to rescan
9797
* them if they haven't changed since the last time we looked.
9898
*/
99-
private final Map<String, SnapshotDirectoryInfo> snapshots = new HashMap<>();
99+
private ImmutableMap<String, SnapshotDirectoryInfo> snapshots = ImmutableMap.of();
100100
private final Timer refreshTimer;
101101

102102
/**
@@ -184,7 +184,7 @@ public synchronized void triggerCacheRefreshForTesting() {
184184
// XXX this is inefficient to synchronize on the method, when what we really need to guard against
185185
// is an illegal access to the cache. Really we could do a mutex-guarded pointer swap on the
186186
// cache, but that seems overkill at the moment and isn't necessarily a bottleneck.
187-
public synchronized Iterable<FileStatus> getUnreferencedFiles(Iterable<FileStatus> files,
187+
public Iterable<FileStatus> getUnreferencedFiles(Iterable<FileStatus> files,
188188
final SnapshotManager snapshotManager) throws IOException {
189189
List<FileStatus> unReferencedFiles = Lists.newArrayList();
190190
List<String> snapshotsInProgress = null;
@@ -200,13 +200,17 @@ public synchronized Iterable<FileStatus> getUnreferencedFiles(Iterable<FileStatu
200200
"skip to clean the HFiles this time");
201201
return unReferencedFiles;
202202
}
203+
ImmutableSet<String> currentCache = cache;
203204
for (FileStatus file : files) {
204205
String fileName = file.getPath().getName();
205-
if (!refreshed && !cache.contains(fileName)) {
206-
refreshCache();
207-
refreshed = true;
206+
if (!refreshed && !currentCache.contains(fileName)) {
207+
synchronized (this) {
208+
refreshCache();
209+
currentCache = cache;
210+
refreshed = true;
211+
}
208212
}
209-
if (cache.contains(fileName)) {
213+
if (currentCache.contains(fileName)) {
210214
continue;
211215
}
212216
if (snapshotsInProgress == null) {
@@ -235,22 +239,23 @@ private void refreshCache() throws IOException {
235239

236240
// clear the cache, as in the below code, either we will also clear the snapshots, or we will
237241
// refill the file name cache again.
238-
this.cache.clear();
239242
if (ArrayUtils.isEmpty(snapshotDirs)) {
240243
// remove all the remembered snapshots because we don't have any left
241244
if (LOG.isDebugEnabled() && this.snapshots.size() > 0) {
242245
LOG.debug("No snapshots on-disk, clear cache");
243246
}
244-
this.snapshots.clear();
247+
this.snapshots = ImmutableMap.of();
248+
this.cache = ImmutableSet.of();
245249
return;
246250
}
247251

252+
ImmutableSet.Builder<String> cacheBuilder = ImmutableSet.builder();
253+
ImmutableMap.Builder<String, SnapshotDirectoryInfo> snapshotsBuilder = ImmutableMap.builder();
248254
// iterate over all the cached snapshots and see if we need to update some, it is not an
249255
// expensive operation if we do not reload the manifest of snapshots.
250-
Map<String, SnapshotDirectoryInfo> newSnapshots = new HashMap<>();
251256
for (FileStatus snapshotDir : snapshotDirs) {
252257
String name = snapshotDir.getPath().getName();
253-
SnapshotDirectoryInfo files = this.snapshots.remove(name);
258+
SnapshotDirectoryInfo files = snapshots.get(name);
254259
// if we don't know about the snapshot or its been modified, we need to update the
255260
// files the latter could occur where I create a snapshot, then delete it, and then make a
256261
// new snapshot with the same name. We will need to update the cache the information from
@@ -262,19 +267,20 @@ private void refreshCache() throws IOException {
262267
files = new SnapshotDirectoryInfo(snapshotDir.getModificationTime(), storedFiles);
263268
}
264269
// add all the files to cache
265-
this.cache.addAll(files.getFiles());
266-
newSnapshots.put(name, files);
270+
cacheBuilder.addAll(files.getFiles());
271+
snapshotsBuilder.put(name, files);
267272
}
268273
// set the snapshots we are tracking
269-
this.snapshots.clear();
270-
this.snapshots.putAll(newSnapshots);
274+
this.snapshots = snapshotsBuilder.build();
275+
this.cache = cacheBuilder.build();
271276
}
272277

273278
List<String> getSnapshotsInProgress() throws IOException {
274279
List<String> snapshotInProgress = Lists.newArrayList();
275280
// only add those files to the cache, but not to the known snapshots
276281

277-
FileStatus[] snapshotsInProgress = CommonFSUtils.listStatus(this.workingFs, this.workingSnapshotDir);
282+
FileStatus[] snapshotsInProgress = CommonFSUtils.listStatus(this.workingFs,
283+
this.workingSnapshotDir);
278284

279285
if (!ArrayUtils.isEmpty(snapshotsInProgress)) {
280286
for (FileStatus snapshot : snapshotsInProgress) {
@@ -301,11 +307,10 @@ public void run() {
301307
} catch (IOException e) {
302308
LOG.warn("Failed to refresh snapshot hfile cache!", e);
303309
// clear all the cached entries if we meet an error
304-
cache.clear();
305-
snapshots.clear();
310+
cache = ImmutableSet.of();
311+
snapshots = ImmutableMap.of();
306312
}
307313
}
308-
309314
}
310315
}
311316

@@ -315,7 +320,6 @@ public void stop(String why) {
315320
this.stop = true;
316321
this.refreshTimer.cancel();
317322
}
318-
319323
}
320324

321325
@Override

hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotHFileCleaner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class SnapshotHFileCleaner extends BaseHFileCleanerDelegate {
6363
private MasterServices master;
6464

6565
@Override
66-
public synchronized Iterable<FileStatus> getDeletableFiles(Iterable<FileStatus> files) {
66+
public Iterable<FileStatus> getDeletableFiles(Iterable<FileStatus> files) {
6767
try {
6868
return cache.getUnreferencedFiles(files, master.getSnapshotManager());
6969
} catch (CorruptedSnapshotException cse) {

0 commit comments

Comments
 (0)