[
https://issues.apache.org/jira/browse/HBASE-30285?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
ASF GitHub Bot updated HBASE-30285:
-----------------------------------
Labels: pull-request-available (was: )
> BucketCache shutdown/disable does not release backingMap-owned BucketEntry
> references
> -------------------------------------------------------------------------------------
>
> Key: HBASE-30285
> URL: https://issues.apache.org/jira/browse/HBASE-30285
> Project: HBase
> Issue Type: Bug
> Reporter: Minwoo Kang
> Assignee: Minwoo Kang
> Priority: Minor
> Labels: pull-request-available
>
> h2. Description
> {{BucketCache}} does not release the reference owned by {{backingMap}} when
> the cache is shut down or disabled.
> A newly created {{BucketEntry}} has an initial reference count of 1. This
> reference is owned by {{BucketCache.backingMap}}.
> For shared-memory IO engines, {{BucketCache.getBlock()}} retains the same
> {{RefCnt}} before returning a cached block. After the caller releases the
> returned block, the backing map reference remains with a count of 1.
> Normal eviction removes the map entry under the offset write lock and calls
> {{blockEvicted()}}. {{blockEvicted()}} calls {{BucketEntry.markAsEvicted()}},
> which releases the backing map reference.
> The non-persistent path in {{BucketCache.disableCache()}} instead calls
> {{backingMap.clear()}} directly. This removes the map references without
> calling {{markAsEvicted()}}. Each affected {{BucketEntry}} therefore retains
> a reference count of 1.
> The persistent shutdown path needs the backing map for serialization, but it
> also does not release the owner references after serialization completes
> h2. Reproduction
> Add the following deterministic test to
> {{hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/bucket/TestBucketCacheRefCnt.java}}.
> {code:java}
> @Test
> public void testShutdownReleasesBackingMapReference() throws Exception {
> ByteBuffAllocator alloc =
> ByteBuffAllocator.create(HBaseConfiguration.create(), true);
> HFileBlock blockToCache = createBlock(200, 1020, alloc);
> HFileBlock blockFromCache = null;
> try {
> cache = create(1, 1000);
> BlockCacheKey key = createKey("testShutdownReleasesBackingMapReference",
> 200);
> cache.cacheBlock(key, blockToCache);
> waitUntilFlushedToCache(cache, key);
> blockFromCache = (HFileBlock) cache.getBlock(key, false, false, false);
> assertNotNull(blockFromCache);
> assertEquals(2, blockFromCache.refCnt());
> blockFromCache.release();
> assertEquals(1, blockFromCache.refCnt());
> cache.shutdown();
> cache = null;
> assertEquals(0, blockFromCache.refCnt(),
> "BucketCache.shutdown must release the backingMap reference for every
> BucketEntry");
> } finally {
> if (cache != null) {
> cache.shutdown();
> }
> if (blockFromCache != null) {
> while (blockFromCache.refCnt() > 0) {
> blockFromCache.release();
> }
> }
> while (blockToCache.refCnt() > 0) {
> blockToCache.release();
> }
> alloc.clean();
> }
> }
> {code}
> h2. Expected behavior
> {{BucketCache}} should release each reference owned by {{backingMap}} exactly
> once when the entry is discarded.
> References held by in-flight callers must remain valid until those callers
> release them.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)