Vladimir Rodionov created HBASE-30412:
-----------------------------------------

             Summary: Fix block replacement accounting and reference handling 
in LruBlockCache/LruCacheEngine
                 Key: HBASE-30412
                 URL: https://issues.apache.org/jira/browse/HBASE-30412
             Project: HBase
          Issue Type: New Feature
          Components: BlockCache
    Affects Versions: 2.6.7, 2.5.16, 3.0.0, 4.0.0-alpha-1
            Reporter: Vladimir Rodionov
            Assignee: Vladimir Rodionov
             Fix For: 4.0.0-alpha-1, 3.0.1, 2.6.8, 2.5.17


h2. Description

{{LruBlockCache}}  contain a block replacement path used when
{{BlockCacheUtil.shouldReplaceExistingCacheBlock(...)}} allows an existing 
cached block to be replaced.

The current sequence is approximately:

{code:java}
LruCachedBlock cachedBlock = map.get(cacheKey);
if (
  cachedBlock != null && !BlockCacheUtil.shouldReplaceExistingCacheBlock(this, 
cacheKey, buf)
) {
  return;
}

Cacheable referencedBlock = asReferencedHeapBlock(buf);
cachedBlock = new LruCachedBlock(cacheKey, referencedBlock, 
count.incrementAndGet(), inMemory);

long newSize = updateSizeMetrics(cachedBlock, false);
map.put(cacheKey, cachedBlock);
elements.incrementAndGet();
{code}

When replacement is allowed, {{map.put()}} overwrites the previous 
{{LruCachedBlock}}.

The previous cached entry is not removed through the normal eviction/removal 
path before the new
entry is accounted for. As a result, the old cache-owned buffer reference may 
not be released and
the old block's size and block-count accounting may remain included in cache 
statistics.

Repeated replacements can therefore cause cache occupancy and block counters to 
diverge from the
actual contents of the backing map and may retain block references longer than 
intended.

h2. Proposed Changes

* Make replacement of an existing {{LruCachedBlock}} atomic with respect to the 
backing map.
* Perform removal accounting against the actual entry being replaced.
* Release the cache-owned reference held by the replaced block.
* Subtract the replaced block's size from total and block-type-specific size 
counters.
* Update element and block-type counters correctly for replacement rather than 
treating the
  operation as an additional insertion.
* Preserve the behavior of 
{{BlockCacheUtil.shouldReplaceExistingCacheBlock(...)}}.
* Preserve existing cache hit/miss and eviction statistics semantics.
* Add tests covering repeated replacement of the same {{BlockCacheKey}}.

h2. Concurrency Considerations

The replacement operation should account for concurrent changes to the same 
cache key.

The implementation should avoid performing accounting based on an entry 
obtained by an earlier
{{map.get()}} if that entry is no longer the value being replaced.

Removal/reference accounting must be applied to the actual previous mapping 
replaced by the
operation.

h2. Acceptance Criteria

* Replacing an existing cached block releases the cache-owned reference of the 
replaced block.
* Cache size accounting reflects only the currently cached replacement block.
* {{elements}} and block-type element counters do not increase merely because 
an existing key is
  replaced.
* Repeated replacements of the same cache key do not cause cache-size or 
block-count drift.
* Replacement remains safe under concurrent access/replacement of the same 
cache key.
* Existing HBASE-20447 replacement behavior is preserved.
* Tests verify reference-count and cache-accounting behavior for block 
replacement.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to