2020import java .io .IOException ;
2121import java .util .Collection ;
2222import java .util .HashMap ;
23- import java .util .HashSet ;
2423import java .util .List ;
2524import java .util .Map ;
26- import java .util .Set ;
2725import java .util .Timer ;
2826import java .util .TimerTask ;
2927import java .util .concurrent .locks .Lock ;
3634import org .apache .hadoop .hbase .snapshot .CorruptedSnapshotException ;
3735import org .apache .hadoop .hbase .snapshot .SnapshotDescriptionUtils ;
3836import 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 ;
3939import org .apache .yetus .audience .InterfaceAudience ;
4040import org .apache .yetus .audience .InterfaceStability ;
4141import 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
0 commit comments