5858import org .apache .hadoop .hbase .testclassification .IOTests ;
5959import org .apache .hadoop .hbase .testclassification .LargeTests ;
6060import org .apache .hadoop .hbase .util .Pair ;
61+ import org .apache .hadoop .hbase .util .Threads ;
6162import org .junit .After ;
6263import org .junit .Assert ;
6364import org .junit .Before ;
@@ -119,7 +120,6 @@ public MockedBucketCache(String ioEngineName, long capacity, int blockSize, int[
119120 int writerThreads , int writerQLen , String persistencePath ) throws IOException {
120121 super (ioEngineName , capacity , blockSize , bucketSizes , writerThreads , writerQLen ,
121122 persistencePath );
122- super .wait_when_cache = true ;
123123 }
124124
125125 @ Override
@@ -241,16 +241,16 @@ public static void waitUntilAllFlushedToBucket(BucketCache cache) throws Interru
241241 // BucketCache.cacheBlock is async, it first adds block to ramCache and writeQueue, then writer
242242 // threads will flush it to the bucket and put reference entry in backingMap.
243243 private void cacheAndWaitUntilFlushedToBucket (BucketCache cache , BlockCacheKey cacheKey ,
244- Cacheable block ) throws InterruptedException {
245- cache .cacheBlock (cacheKey , block );
244+ Cacheable block , boolean waitWhenCache ) throws InterruptedException {
245+ cache .cacheBlock (cacheKey , block , false , waitWhenCache );
246246 waitUntilFlushedToBucket (cache , cacheKey );
247247 }
248248
249249 @ Test
250250 public void testMemoryLeak () throws Exception {
251251 final BlockCacheKey cacheKey = new BlockCacheKey ("dummy" , 1L );
252252 cacheAndWaitUntilFlushedToBucket (cache , cacheKey ,
253- new CacheTestUtils .ByteArrayCacheable (new byte [10 ]));
253+ new CacheTestUtils .ByteArrayCacheable (new byte [10 ]), true );
254254 long lockId = cache .backingMap .get (cacheKey ).offset ();
255255 ReentrantReadWriteLock lock = cache .offsetLock .getLock (lockId );
256256 lock .writeLock ().lock ();
@@ -265,7 +265,7 @@ public void run() {
265265 cache .blockEvicted (cacheKey , cache .backingMap .remove (cacheKey ), true , true );
266266 assertEquals (0 , cache .getBlockCount ());
267267 cacheAndWaitUntilFlushedToBucket (cache , cacheKey ,
268- new CacheTestUtils .ByteArrayCacheable (new byte [10 ]));
268+ new CacheTestUtils .ByteArrayCacheable (new byte [10 ]), true );
269269 assertEquals (1 , cache .getBlockCount ());
270270 lock .writeLock ().unlock ();
271271 evictThread .join ();
@@ -341,7 +341,8 @@ private void testRetrievalUtils(Path testDir, String ioEngineName)
341341 bucketCache .cacheBlock (block .getBlockName (), block .getBlock ());
342342 }
343343 for (HFileBlockPair block : blocks ) {
344- cacheAndWaitUntilFlushedToBucket (bucketCache , block .getBlockName (), block .getBlock ());
344+ cacheAndWaitUntilFlushedToBucket (bucketCache , block .getBlockName (), block .getBlock (),
345+ false );
345346 }
346347 usedSize = bucketCache .getAllocator ().getUsedSize ();
347348 assertNotEquals (0 , usedSize );
@@ -403,7 +404,8 @@ public void testRetrieveFromFileWithoutPersistence() throws Exception {
403404 bucketCache .cacheBlock (block .getBlockName (), block .getBlock ());
404405 }
405406 for (HFileBlockPair block : blocks ) {
406- cacheAndWaitUntilFlushedToBucket (bucketCache , block .getBlockName (), block .getBlock ());
407+ cacheAndWaitUntilFlushedToBucket (bucketCache , block .getBlockName (), block .getBlock (),
408+ false );
407409 }
408410 usedSize = bucketCache .getAllocator ().getUsedSize ();
409411 assertNotEquals (0 , usedSize );
@@ -786,7 +788,7 @@ public void testFreeBucketEntryRestoredFromFile() throws Exception {
786788
787789 for (HFileBlockPair hfileBlockPair : hfileBlockPairs ) {
788790 cacheAndWaitUntilFlushedToBucket (bucketCache , hfileBlockPair .getBlockName (),
789- hfileBlockPair .getBlock ());
791+ hfileBlockPair .getBlock (), false );
790792 }
791793 usedByteSize = bucketCache .getAllocator ().getUsedSize ();
792794 assertNotEquals (0 , usedByteSize );
@@ -811,4 +813,63 @@ public void testFreeBucketEntryRestoredFromFile() throws Exception {
811813 }
812814 }
813815
816+ /**
817+ * This test is for HBASE-26295, {@link BucketEntry} which is restored from a persistence file
818+ * could not be freed even if corresponding {@link HFileBlock} is evicted from
819+ * {@link BucketCache}.
820+ */
821+ @ Test
822+ public void testBlockAdditionWaitWhenCache () throws Exception {
823+ try {
824+ final Path dataTestDir = createAndGetTestDir ();
825+
826+ String ioEngineName = "file:" + dataTestDir + "/bucketNoRecycler.cache" ;
827+ String persistencePath = dataTestDir + "/bucketNoRecycler.persistence" ;
828+
829+ BucketCache bucketCache = new BucketCache (ioEngineName , capacitySize , constructedBlockSize ,
830+ constructedBlockSizes , 1 , 1 , persistencePath );
831+ long usedByteSize = bucketCache .getAllocator ().getUsedSize ();
832+ assertEquals (0 , usedByteSize );
833+
834+ HFileBlockPair [] hfileBlockPairs =
835+ CacheTestUtils .generateHFileBlocks (constructedBlockSize , 10 );
836+ // Add blocks
837+ for (HFileBlockPair hfileBlockPair : hfileBlockPairs ) {
838+ bucketCache .cacheBlock (hfileBlockPair .getBlockName (), hfileBlockPair .getBlock (), false ,
839+ true );
840+ }
841+
842+ // Max wait for 10 seconds.
843+ long timeout = 10000 ;
844+ // Wait for blocks size to match the number of blocks.
845+ while (bucketCache .backingMap .size () != 10 ) {
846+ if (timeout <= 0 ) break ;
847+ Threads .sleep (100 );
848+ timeout = -100 ;
849+ }
850+ for (HFileBlockPair hfileBlockPair : hfileBlockPairs ) {
851+ assertTrue (bucketCache .backingMap .containsKey (hfileBlockPair .getBlockName ()));
852+ }
853+ usedByteSize = bucketCache .getAllocator ().getUsedSize ();
854+ assertNotEquals (0 , usedByteSize );
855+ // persist cache to file
856+ bucketCache .shutdown ();
857+ assertTrue (new File (persistencePath ).exists ());
858+
859+ // restore cache from file
860+ bucketCache = new BucketCache (ioEngineName , capacitySize , constructedBlockSize ,
861+ constructedBlockSizes , writeThreads , writerQLen , persistencePath );
862+ assertFalse (new File (persistencePath ).exists ());
863+ assertEquals (usedByteSize , bucketCache .getAllocator ().getUsedSize ());
864+
865+ for (HFileBlockPair hfileBlockPair : hfileBlockPairs ) {
866+ BlockCacheKey blockCacheKey = hfileBlockPair .getBlockName ();
867+ bucketCache .evictBlock (blockCacheKey );
868+ }
869+ assertEquals (0 , bucketCache .getAllocator ().getUsedSize ());
870+ assertEquals (0 , bucketCache .backingMap .size ());
871+ } finally {
872+ HBASE_TESTING_UTILITY .cleanupTestDir ();
873+ }
874+ }
814875}
0 commit comments