You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2012/07/13 01:16:46 UTC
svn commit: r1361000 - in /hbase/branches/0.89-fb/src:
main/java/org/apache/hadoop/hbase/io/hfile/
test/java/org/apache/hadoop/hbase/client/
test/java/org/apache/hadoop/hbase/io/hfile/
test/java/org/apache/hadoop/hbase/regionserver/
Author: mbautin
Date: Thu Jul 12 23:16:46 2012
New Revision: 1361000
URL: http://svn.apache.org/viewvc?rev=1361000&view=rev
Log:
[jira] [HBASE-6366] [89-fb] Delay eviction on close
Author: michalgr
Summary:
Delay eviction on close.
Since now evictBlocksByHfileName does not evict blocks immediately. It adds name of the file to list of recently closed files. During next eviction blocks corresponding to files on list are evicted and the list is cleared.
Test Plan: I prepared unit test. It runs ok.
Reviewers: liyintang, kranganathan
Reviewed By: liyintang
CC: JIRA
Differential Revision: https://reviews.facebook.net/D4071
Added:
hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestHelper.java
Modified:
hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/io/hfile/LruBlockCache.java
hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/TestLruBlockCache.java
hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreFile.java
Modified: hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/io/hfile/LruBlockCache.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/io/hfile/LruBlockCache.java?rev=1361000&r1=1360999&r2=1361000&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/io/hfile/LruBlockCache.java (original)
+++ hbase/branches/0.89-fb/src/main/java/org/apache/hadoop/hbase/io/hfile/LruBlockCache.java Thu Jul 12 23:16:46 2012
@@ -25,9 +25,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
+import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
@@ -124,6 +127,9 @@ public class LruBlockCache implements Bl
/** Eviction thread */
private final EvictionThread evictionThread;
+ /** Synchronized list of closed files **/
+ private final List<String> recentlyClosedFiles;
+
/** Statistics thread schedule pool (for heavy debugging, could remove) */
private final ScheduledExecutorService scheduleThreadPool =
Executors.newScheduledThreadPool(1,
@@ -270,6 +276,8 @@ public class LruBlockCache implements Bl
}
this.scheduleThreadPool.scheduleAtFixedRate(new StatisticsThread(this),
statThreadPeriod, statThreadPeriod, TimeUnit.SECONDS);
+
+ this.recentlyClosedFiles = Collections.synchronizedList(new LinkedList<String>());
}
public void setMaxSize(long maxSize) {
@@ -367,27 +375,51 @@ public class LruBlockCache implements Bl
}
/**
- * Evicts all blocks for a specific HFile. This is an
- * expensive operation implemented as a linear-time search through all blocks
- * in the cache. Ideally this should be a search in a log-access-time map.
+ * Adds specific HFile to a list of recently closed files. Next time the eviction happens
+ * all blocks of the File will be evicted.
*
* <p>
* This is used for evict-on-close to remove all blocks of a specific HFile.
*
- * @return the number of blocks evicted
+ * @return 0
*/
@Override
public int evictBlocksByHfileName(String hfileName) {
int numEvicted = 0;
- for (BlockCacheKey key : map.keySet()) {
- if (key.getHfileName().equals(hfileName)) {
- if (evictBlock(key))
- ++numEvicted;
- }
- }
+ recentlyClosedFiles.add(hfileName);
return numEvicted;
}
+ /**
+ * Evicts blocks specified by file names in recentlyClosedFiles list and clears the list.
+ *
+ * @return number of freed bytes
+ */
+ private long doDelayedEviction(){
+ Set<String> closedRecently = new HashSet<String>();
+
+ LOG.debug("Delayed eviction started.");
+
+ synchronized(recentlyClosedFiles){
+ for (String fname : recentlyClosedFiles){
+ closedRecently.add(fname);
+ }
+ recentlyClosedFiles.clear();
+ }
+
+ long bytesFreed = 0;
+ for (CachedBlock block : map.values()){
+ if (closedRecently.contains(block.getCacheKey().getHfileName())){
+ bytesFreed += evictBlock(block);
+ }
+ }
+
+ float freedMB = ((float)bytesFreed)/((float)(1024*1024));
+ LOG.debug("Delayed eviction finished. Freed " + Float.toString(freedMB) + " MB");
+
+ return bytesFreed;
+ }
+
protected long evictBlock(CachedBlock block) {
map.remove(block.getCacheKey());
updateSizeMetrics(block, true);
@@ -395,7 +427,7 @@ public class LruBlockCache implements Bl
stats.evicted(block);
return block.heapSize();
}
-
+
/**
* Multi-threaded call to run the eviction process.
*/
@@ -420,6 +452,12 @@ public class LruBlockCache implements Bl
long bytesToFree = size.get() - minSize();
+
+ if(bytesToFree <= 0) return;
+
+ doDelayedEviction();
+
+ bytesToFree = size.get() - minSize();
LOG.debug("Block cache LRU eviction started. Attempting to free " +
bytesToFree + " bytes");
@@ -806,7 +844,7 @@ public class LruBlockCache implements Bl
}
public final static long CACHE_FIXED_OVERHEAD = ClassSize.align(
- (3 * Bytes.SIZEOF_LONG) + (8 * ClassSize.REFERENCE) +
+ (3 * Bytes.SIZEOF_LONG) + (9 * ClassSize.REFERENCE) +
(5 * Bytes.SIZEOF_FLOAT) + Bytes.SIZEOF_BOOLEAN
+ ClassSize.OBJECT);
Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java?rev=1361000&r1=1360999&r2=1361000&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java Thu Jul 12 23:16:46 2012
@@ -69,6 +69,7 @@ import org.apache.hadoop.hbase.filter.Si
import org.apache.hadoop.hbase.filter.WhileMatchFilter;
import org.apache.hadoop.hbase.io.hfile.BlockCache;
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
+import org.apache.hadoop.hbase.io.hfile.CacheTestHelper;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
@@ -4163,7 +4164,8 @@ public class TestFromClientSide {
cacheConf.setCacheDataOnWrite(true);
cacheConf.setEvictOnClose(true);
BlockCache cache = cacheConf.getBlockCache();
-
+ // Get rid of blocks marked to be evicted.
+ CacheTestHelper.forceDelayedEviction(cache);
// establish baseline stats
long startBlockCount = cache.getBlockCount();
long startBlockHits = cache.getStats().getHitCount();
@@ -4180,6 +4182,7 @@ public class TestFromClientSide {
// flush the data
System.out.println("Flushing cache");
region.flushcache();
+ CacheTestHelper.forceDelayedEviction(cache);
// expect one more block in cache, no change in hits/misses
long expectedBlockCount = startBlockCount + 1;
long expectedBlockHits = startBlockHits;
@@ -4207,6 +4210,7 @@ public class TestFromClientSide {
// flush, one new block
System.out.println("Flushing cache");
region.flushcache();
+ CacheTestHelper.forceDelayedEviction(cache);
assertEquals(++expectedBlockCount, cache.getBlockCount());
assertEquals(expectedBlockHits, cache.getStats().getHitCount());
assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
@@ -4218,6 +4222,7 @@ public class TestFromClientSide {
waitForStoreFileCount(store, 1, 10000); // wait 10 seconds max
assertEquals(1, store.getNumberOfStoreFiles());
expectedBlockCount -= 2; // evicted two blocks, cached none
+ CacheTestHelper.forceDelayedEviction(cache);
assertEquals(expectedBlockCount, cache.getBlockCount());
expectedBlockHits += 2;
assertEquals(expectedBlockMiss, cache.getStats().getMissCount());
Added: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestHelper.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestHelper.java?rev=1361000&view=auto
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestHelper.java (added)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/CacheTestHelper.java Thu Jul 12 23:16:46 2012
@@ -0,0 +1,16 @@
+package org.apache.hadoop.hbase.io.hfile;
+
+import java.lang.reflect.Method;
+
+public class CacheTestHelper {
+ public static void forceDelayedEviction(BlockCache bc) throws Exception{
+ if (bc instanceof LruBlockCache){
+ LruBlockCache lbc = (LruBlockCache)bc;
+ Method doDelayedEvictionMethod = LruBlockCache.class.getDeclaredMethod("doDelayedEviction");
+ doDelayedEvictionMethod.setAccessible(true);
+ doDelayedEvictionMethod.invoke(lbc);
+ }
+ }
+
+
+}
Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/TestLruBlockCache.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/TestLruBlockCache.java?rev=1361000&r1=1360999&r2=1361000&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/TestLruBlockCache.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/io/hfile/TestLruBlockCache.java Thu Jul 12 23:16:46 2012
@@ -374,6 +374,28 @@ public class TestLruBlockCache {
}
+
+ @Test
+ public void testDelayedFileEviction() throws Exception {
+ long maxSize = 100000;
+ long blockSize = calculateBlockSizeDefault(maxSize, 10);
+ String fileName = "testFile";
+ LruBlockCache cache = new LruBlockCache(maxSize,blockSize,false);
+
+ CachedItem [] blocks = generateFileBlocks(fileName, 5, 10000);
+ // Add and get the multi blocks
+ for (CachedItem block : blocks) {
+ cache.cacheBlock(block.cacheKey, block);
+ assertEquals(cache.getBlock(block.cacheKey, true), block);
+ }
+
+ cache.evictBlocksByHfileName(fileName);
+
+ CacheTestHelper.forceDelayedEviction(cache);
+
+ for (CachedItem block : blocks)
+ assertEquals(null, cache.getBlock(block.cacheKey, true));
+ }
// test scan resistance
@Test
@@ -507,6 +529,14 @@ public class TestLruBlockCache {
}
return blocks;
}
+
+ private CachedItem [] generateFileBlocks(String fileName, int numBlocks, int size) {
+ CachedItem [] blocks = new CachedItem[numBlocks];
+ for(int i=0;i<numBlocks;i++) {
+ blocks[i] = new CachedItem(fileName, size, size * i);
+ }
+ return blocks;
+ }
private CachedItem [] generateFixedBlocks(int numBlocks, long size, String pfx) {
return generateFixedBlocks(numBlocks, (int)size, pfx);
@@ -554,6 +584,11 @@ public class TestLruBlockCache {
this.cacheKey = new BlockCacheKey(blockName, 0);
this.size = size;
}
+
+ CachedItem(String blockName, int size, int offset) {
+ this.cacheKey = new BlockCacheKey(blockName, offset);
+ this.size = size;
+ }
/** The size of this item reported to the block cache layer */
@Override
Modified: hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreFile.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreFile.java?rev=1361000&r1=1360999&r2=1361000&view=diff
==============================================================================
--- hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreFile.java (original)
+++ hbase/branches/0.89-fb/src/test/java/org/apache/hadoop/hbase/regionserver/TestStoreFile.java Thu Jul 12 23:16:46 2012
@@ -43,6 +43,7 @@ import org.apache.hadoop.hbase.io.Refere
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.io.hfile.BlockCache;
import org.apache.hadoop.hbase.io.hfile.CacheConfig;
+import org.apache.hadoop.hbase.io.hfile.CacheTestHelper;
import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.io.hfile.HFileDataBlockEncoder;
import org.apache.hadoop.hbase.io.hfile.HFileDataBlockEncoderImpl;
@@ -740,6 +741,10 @@ public class TestStoreFile extends HBase
// Grab the block cache and get the initial hit/miss counts
BlockCache bc = new CacheConfig(conf).getBlockCache();
assertNotNull(bc);
+
+ // Do delayed eviction. Test relies on that.
+ CacheTestHelper.forceDelayedEviction(bc);
+
CacheStats cs = bc.getStats();
long startHit = cs.getHitCount();
long startMiss = cs.getMissCount();
@@ -766,6 +771,7 @@ public class TestStoreFile extends HBase
startMiss += 3;
scanner.close();
reader.close(cacheConf.shouldEvictOnClose());
+ CacheTestHelper.forceDelayedEviction(bc);
// Now write a StoreFile with three blocks, with cache on write on
conf.setBoolean(CacheConfig.CACHE_BLOCKS_ON_WRITE_KEY, true);
@@ -786,6 +792,7 @@ public class TestStoreFile extends HBase
startHit += 3;
scanner.close();
reader.close(cacheConf.shouldEvictOnClose());
+ CacheTestHelper.forceDelayedEviction(bc);
// Let's read back the two files to ensure the blocks exactly match
hsf = new StoreFile(this.fs, pathCowOff, conf, cacheConf,
@@ -823,6 +830,7 @@ public class TestStoreFile extends HBase
readerOne.close(cacheConf.shouldEvictOnClose());
scannerTwo.close();
readerTwo.close(cacheConf.shouldEvictOnClose());
+ CacheTestHelper.forceDelayedEviction(bc);
// Let's close the first file with evict on close turned on
conf.setBoolean("hbase.rs.evictblocksonclose", true);
@@ -831,6 +839,7 @@ public class TestStoreFile extends HBase
StoreFile.BloomType.NONE, NoOpDataBlockEncoder.INSTANCE);
reader = hsf.createReader();
reader.close(cacheConf.shouldEvictOnClose());
+ CacheTestHelper.forceDelayedEviction(bc);
// We should have 3 new evictions
assertEquals(startHit, cs.getHitCount());
@@ -845,6 +854,7 @@ public class TestStoreFile extends HBase
StoreFile.BloomType.NONE, NoOpDataBlockEncoder.INSTANCE);
reader = hsf.createReader();
reader.close(cacheConf.shouldEvictOnClose());
+ CacheTestHelper.forceDelayedEviction(bc);
// We expect no changes
assertEquals(startHit, cs.getHitCount());