diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobFileCache.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobFileCache.java index b709d06..c8b03e8 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobFileCache.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mob/MobFileCache.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.mob; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -30,14 +31,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.util.IdLock; import org.apache.yetus.audience.InterfaceAudience; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.hadoop.hbase.util.IdLock; import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -103,7 +106,7 @@ public class MobFileCache { this.mobFileMaxCacheSize = conf.getInt(MobConstants.MOB_FILE_CACHE_SIZE_KEY, MobConstants.DEFAULT_MOB_FILE_CACHE_SIZE); isCacheEnabled = (mobFileMaxCacheSize > 0); - map = new ConcurrentHashMap<>(mobFileMaxCacheSize); + map = new ConcurrentHashMap<>(2 * mobFileMaxCacheSize); if (isCacheEnabled) { long period = conf.getLong(MobConstants.MOB_CACHE_EVICT_PERIOD, MobConstants.DEFAULT_MOB_CACHE_EVICT_PERIOD); // in seconds @@ -119,10 +122,8 @@ public class MobFileCache { this.scheduleThreadPool.scheduleAtFixedRate(new EvictionThread(this), period, period, TimeUnit.SECONDS); - if (LOG.isDebugEnabled()) { - LOG.debug("MobFileCache enabled with cacheSize=" + mobFileMaxCacheSize + - ", evictPeriods=" + period + "sec, evictRemainRatio=" + evictRemainRatio); - } + LOG.debug("MobFileCache enabled with cacheSize={}, evictPeriods={} sec, evictRemainRatio={}", + mobFileMaxCacheSize, period, evictRemainRatio); } else { LOG.info("MobFileCache disabled"); } @@ -133,39 +134,43 @@ public class MobFileCache { * than the threshold. */ public void evict() { - if (isCacheEnabled) { - // Ensure only one eviction at a time - if (!evictionLock.tryLock()) { - return; - } + if (!isCacheEnabled) { + return; + } + if (!evictionLock.tryLock()) { + return; + } + Collection evictedFiles = Collections.emptyList(); + try { printStatistics(); - List evictedFiles = new ArrayList<>(); - try { - if (map.size() <= mobFileMaxCacheSize) { - return; - } - List files = new ArrayList<>(map.values()); - Collections.sort(files); + if (shouldEvict()) { int start = (int) (mobFileMaxCacheSize * evictRemainRatio); if (start >= 0) { - for (int i = start; i < files.size(); i++) { - String name = files.get(i).getFileName(); - CachedMobFile evictedFile = map.remove(name); - if (evictedFile != null) { - evictedFiles.add(evictedFile); + int evictCount = this.map.size() - start; + + Collection files = this.map.values().stream() + .sorted(Collections.reverseOrder()) + .limit(evictCount) + .collect(Collectors.toList()); + + evictedFiles = new ArrayList<>(evictCount); + for (CachedMobFile file : files) { + boolean removed = map.remove(file.getFileName(), file); + if (removed) { + evictedFiles.add(file); } } } - } finally { - evictionLock.unlock(); - } - // EvictionLock is released. Close the evicted files one by one. - // The closes are sync in the closeFile method. - for (CachedMobFile evictedFile : evictedFiles) { - closeFile(evictedFile); } - evictedFileCount.add(evictedFiles.size()); + } finally { + evictionLock.unlock(); + } + // EvictionLock is released. Close the evicted files one by one. + // The closes are sync in the closeFile method. + for (CachedMobFile evictedFile : evictedFiles) { + closeFile(evictedFile); } + evictedFileCount.add(evictedFiles.size()); } /** @@ -184,7 +189,7 @@ public class MobFileCache { evictedFileCount.increment(); } } catch (IOException e) { - LOG.error("Failed to evict the file " + fileName, e); + LOG.error("Failed to evict the file {}", fileName, e); } finally { if (lockEntry != null) { keyLock.releaseLockEntry(lockEntry); @@ -199,37 +204,36 @@ public class MobFileCache { * @param path The file path. * @param cacheConf The current MobCacheConfig * @return A opened mob file. - * @throws IOException + * @throws IOException if the mob file cannot be opened */ public MobFile openFile(FileSystem fs, Path path, MobCacheConfig cacheConf) throws IOException { if (!isCacheEnabled) { MobFile mobFile = MobFile.create(fs, path, conf, cacheConf); mobFile.open(); return mobFile; - } else { - String fileName = path.getName(); - CachedMobFile cached = map.get(fileName); - IdLock.Entry lockEntry = keyLock.getLockEntry(fileName.hashCode()); - try { + } + String fileName = path.getName(); + CachedMobFile cached = map.get(fileName); + IdLock.Entry lockEntry = keyLock.getLockEntry(fileName.hashCode()); + try { + if (cached == null) { + cached = map.get(fileName); if (cached == null) { - cached = map.get(fileName); - if (cached == null) { - if (map.size() > mobFileMaxCacheSize) { - evict(); - } - cached = CachedMobFile.create(fs, path, conf, cacheConf); - cached.open(); - map.put(fileName, cached); - miss.increment(); + if (shouldEvict()) { + evict(); } + cached = CachedMobFile.create(fs, path, conf, cacheConf); + cached.open(); + map.put(fileName, cached); + miss.increment(); } - cached.open(); - cached.access(count.incrementAndGet()); - } finally { - keyLock.releaseLockEntry(lockEntry); } - return cached; + cached.open(); + cached.access(count.incrementAndGet()); + } finally { + keyLock.releaseLockEntry(lockEntry); } + return cached; } /** @@ -239,14 +243,12 @@ public class MobFileCache { public void closeFile(MobFile file) { IdLock.Entry lockEntry = null; try { - if (!isCacheEnabled) { - file.close(); - } else { + if (isCacheEnabled) { lockEntry = keyLock.getLockEntry(file.getFileName().hashCode()); - file.close(); } + file.close(); } catch (IOException e) { - LOG.error("MobFileCache, Exception happen during close " + file.getFileName(), e); + LOG.error("MobFileCache, Exception happen during close {}", file.getFileName(), e); } finally { if (lockEntry != null) { keyLock.releaseLockEntry(lockEntry); @@ -256,25 +258,27 @@ public class MobFileCache { public void shutdown() { this.scheduleThreadPool.shutdown(); - for (int i = 0; i < 100; i++) { - if (!this.scheduleThreadPool.isShutdown()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - LOG.warn("Interrupted while sleeping"); - Thread.currentThread().interrupt(); - break; - } - } + boolean terminated = false; + try { + terminated = this.scheduleThreadPool.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + LOG.warn("Interrupted while sleeping"); } - - if (!this.scheduleThreadPool.isShutdown()) { + if (!terminated) { List runnables = this.scheduleThreadPool.shutdownNow(); - LOG.debug("Still running " + runnables); + LOG.debug("Still running {}", runnables); } } /** + * @return true if one or more entries should be evicted from the cache + * (because the cache is full) + */ + private boolean shouldEvict() { + return this.map.size() > this.mobFileMaxCacheSize; + } + + /** * Gets the count of cached mob files. * @return The count of the cached mob files. */ @@ -328,5 +332,4 @@ public class MobFileCache { lastMiss += missed; lastEvictedFileCount += evicted; } - }