VladRodionov commented on code in PR #8766:
URL: https://github.com/apache/hbase/pull/8766#discussion_r4291318026


##########
hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdaptiveLruCachePlacementAdmissionPolicy.java:
##########
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.io.hfile.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.hfile.BlockCacheKey;
+import org.apache.hadoop.hbase.io.hfile.Cacheable;
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Placement and admission policy implementing AdaptiveLRU behavior using a 
native
+ * {@link LruCacheEngine}.
+ * <p>
+ * The policy preserves the adaptive admission behavior of the legacy {@code 
LruAdaptiveBlockCache}.
+ * Under sustained LRU eviction pressure, it reduces the percentage of data 
blocks admitted to the
+ * first-level cache. When eviction pressure decreases, data-block admission 
is gradually restored.
+ * </p>
+ * <p>
+ * Non-data blocks are not filtered by the adaptive algorithm.
+ * </p>
+ */
[email protected]
+public final class AdaptiveLruCachePlacementAdmissionPolicy
+  implements CachePlacementAdmissionPolicy {
+
+  private static final Logger LOG =
+    LoggerFactory.getLogger(AdaptiveLruCachePlacementAdmissionPolicy.class);
+
+  private static final String LRU_CACHE_HEAVY_EVICTION_COUNT_LIMIT =
+    "hbase.lru.cache.heavy.eviction.count.limit";
+
+  private static final int DEFAULT_LRU_CACHE_HEAVY_EVICTION_COUNT_LIMIT = 
Integer.MAX_VALUE;
+
+  private static final String LRU_CACHE_HEAVY_EVICTION_MB_SIZE_LIMIT =
+    "hbase.lru.cache.heavy.eviction.mb.size.limit";
+
+  private static final long DEFAULT_LRU_CACHE_HEAVY_EVICTION_MB_SIZE_LIMIT = 
500L;
+
+  private static final String LRU_CACHE_HEAVY_EVICTION_OVERHEAD_COEFFICIENT =
+    "hbase.lru.cache.heavy.eviction.overhead.coefficient";
+
+  private static final float 
DEFAULT_LRU_CACHE_HEAVY_EVICTION_OVERHEAD_COEFFICIENT = 0.01f;
+
+  private static final long EVICTION_EVALUATION_PERIOD_MS = 10_000L;
+
+  private static final int MIN_CACHE_DATA_BLOCK_PERCENT = 1;
+
+  private static final int MAX_CACHE_DATA_BLOCK_PERCENT = 100;
+
+  private static final int MAX_ADMISSION_REDUCTION_PER_PERIOD = 15;
+
+  private static final CachePlacementAdmissionPolicy DELEGATE =
+    DefaultHBaseCachePlacementAdmissionPolicy.INSTANCE;
+
+  private final int heavyEvictionCountLimit;
+
+  private final long heavyEvictionMbSizeLimit;
+
+  private final float heavyEvictionOverheadCoefficient;
+
+  private volatile int cacheDataBlockPercent = MAX_CACHE_DATA_BLOCK_PERCENT;
+
+  private long freedSumMb;
+
+  private int heavyEvictionCount;
+
+  private long evaluationStartTime;
+
+  /**
+   * Creates an AdaptiveLRU placement/admission policy from configuration.
+   * @param conf cache configuration
+   * @throws NullPointerException if {@code conf} is {@code null}
+   */
+  public AdaptiveLruCachePlacementAdmissionPolicy(Configuration conf) {
+    Objects.requireNonNull(conf, "conf must not be null");
+
+    this.heavyEvictionCountLimit = 
Math.max(conf.getInt(LRU_CACHE_HEAVY_EVICTION_COUNT_LIMIT,
+      DEFAULT_LRU_CACHE_HEAVY_EVICTION_COUNT_LIMIT), 0);
+
+    this.heavyEvictionMbSizeLimit = 
Math.max(conf.getLong(LRU_CACHE_HEAVY_EVICTION_MB_SIZE_LIMIT,
+      DEFAULT_LRU_CACHE_HEAVY_EVICTION_MB_SIZE_LIMIT), 1L);
+
+    float configuredCoefficient = 
conf.getFloat(LRU_CACHE_HEAVY_EVICTION_OVERHEAD_COEFFICIENT,
+      DEFAULT_LRU_CACHE_HEAVY_EVICTION_OVERHEAD_COEFFICIENT);
+    configuredCoefficient = Math.min(configuredCoefficient, 1.0f);
+    configuredCoefficient = Math.max(configuredCoefficient, 0.001f);
+    this.heavyEvictionOverheadCoefficient = configuredCoefficient;
+
+    this.evaluationStartTime = EnvironmentEdgeManager.currentTime();
+  }
+
+  /**
+   * Decides whether a block should be admitted into the cache.
+   * <p>
+   * In a single-tier topology, adaptive rejection means the data block is not 
cached. In a tiered
+   * topology, admission remains enabled because adaptive filtering applies 
specifically to the L1
+   * placement decision rather than to the entire cache hierarchy.
+   * </p>
+   * @param cacheKey     block cache key
+   * @param block        block to cache
+   * @param context      cache write context
+   * @param priority     admission priority
+   * @param topologyView read-only topology view
+   * @return admission decision
+   */
+  @Override
+  public AdmissionDecision shouldAdmit(BlockCacheKey cacheKey, Cacheable block,
+    CacheWriteContext context, AdmissionPriority priority, CacheTopologyView 
topologyView) {
+    Objects.requireNonNull(cacheKey, "cacheKey must not be null");
+    Objects.requireNonNull(block, "block must not be null");
+    Objects.requireNonNull(context, "context must not be null");
+    Objects.requireNonNull(priority, "priority must not be null");
+    Objects.requireNonNull(topologyView, "topologyView must not be null");
+
+    AdmissionDecision decision =
+      DELEGATE.shouldAdmit(cacheKey, block, context, priority, topologyView);
+    if (!decision.isAdmitted()) {
+      return decision;
+    }
+
+    if (
+      topologyView.getType() == CacheTopologyType.SINGLE_TIER
+        && !shouldCacheInFirstLevel(cacheKey, block)
+    ) {
+      return AdmissionDecision.reject("Rejected by AdaptiveLRU data-block 
admission");
+    }
+
+    return decision;
+  }
+
+  /**
+   * Selects the target tier or tiers for an admitted block.
+   * <p>
+   * The default HBase placement decision is preserved unless AdaptiveLRU 
rejects a data block from
+   * L1. In a tiered topology this removes L1 from the target set while 
retaining other selected
+   * tiers such as L2.
+   * </p>
+   * @param cacheKey     block cache key
+   * @param block        block to cache
+   * @param context      cache write context
+   * @param topologyView read-only topology view
+   * @return cache tier decision
+   */
+  @Override
+  public TierDecision selectTier(BlockCacheKey cacheKey, Cacheable block, 
CacheWriteContext context,
+    CacheTopologyView topologyView) {
+    Objects.requireNonNull(cacheKey, "cacheKey must not be null");
+    Objects.requireNonNull(block, "block must not be null");
+    Objects.requireNonNull(context, "context must not be null");
+    Objects.requireNonNull(topologyView, "topologyView must not be null");
+
+    TierDecision decision = DELEGATE.selectTier(cacheKey, block, context, 
topologyView);
+
+    if (!decision.getTiers().contains(CacheTier.L1) || 
shouldCacheInFirstLevel(cacheKey, block)) {
+      return decision;
+    }
+
+    List<CacheTier> tiers = new ArrayList<>();
+    for (CacheTier tier : decision.getTiers()) {
+      if (tier != CacheTier.L1) {
+        tiers.add(tier);
+      }
+    }
+

Review Comment:
   Yes, this is a bug. If filtering L1 leaves no remaining target tier, the 
policy should return TierDecision.none() rather than construct an empty 
multi-tier decision. I added the explicit empty-result handling and a 
regression test for the L2-unavailable fallback case.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to