This is an automated email from the ASF dual-hosted git repository.

liuxiaocs7 pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-3 by this push:
     new eb3111eccb8 HBASE-30343 Per-table avgStoreFileAge overwrites instead 
of accumulating store ages (#8572)
eb3111eccb8 is described below

commit eb3111eccb8eb2e2d6d888c52adc8bd2e099431e
Author: Xiao Liu <[email protected]>
AuthorDate: Thu Aug 27 21:51:14 2026 +0800

    HBASE-30343 Per-table avgStoreFileAge overwrites instead of accumulating 
store ages (#8572)
    
    Signed-off by: Peng Lu <[email protected]>
---
 .../MetricsTableWrapperAggregateImpl.java          |   4 +-
 .../TestMetricsTableWrapperAggregate.java          | 104 +++++++++++++++++++++
 2 files changed, 106 insertions(+), 2 deletions(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsTableWrapperAggregateImpl.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsTableWrapperAggregateImpl.java
index 29d0d7cc008..00a4c1a48d5 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsTableWrapperAggregateImpl.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsTableWrapperAggregateImpl.java
@@ -91,8 +91,8 @@ public class MetricsTableWrapperAggregateImpl implements 
MetricsTableWrapperAggr
                 Math.min(mt.minStoreFileAge, 
store.getMinStoreFileAge().getAsLong());
             }
             if (store.getAvgStoreFileAge().isPresent()) {
-              mt.totalStoreFileAge =
-                (long) store.getAvgStoreFileAge().getAsDouble() * 
store.getStorefilesCount();
+              mt.totalStoreFileAge +=
+                (long) (store.getAvgStoreFileAge().getAsDouble() * 
store.getStorefilesCount());
             }
             mt.storeCount += 1;
 
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestMetricsTableWrapperAggregate.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestMetricsTableWrapperAggregate.java
new file mode 100644
index 00000000000..7a0722dda47
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestMetricsTableWrapperAggregate.java
@@ -0,0 +1,104 @@
+/*
+ * 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.regionserver;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.testclassification.RegionServerTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
+
+@Tag(SmallTests.TAG)
+@Tag(RegionServerTests.TAG)
+public class TestMetricsTableWrapperAggregate {
+
+  private static final TableName TABLE = TableName.valueOf("table1");
+
+  @Test
+  public void testAvgStoreFileAgeAccumulatesAcrossStores() throws IOException {
+    // Two regions of the same table, three stores in total; per store: 
(count, avg, max, min).
+    HStore storeA = getMockedStore("cf1", 2, 10.0, 15, 5);
+    HStore storeB = getMockedStore("cf2", 3, 20.0, 30, 1);
+    HStore storeC = getMockedStore("cf3", 5, 4.0, 8, 2);
+
+    HRegion region1 = getMockedRegion(Lists.newArrayList(storeA, storeB));
+    HRegion region2 = getMockedRegion(Lists.newArrayList(storeC));
+    List<HRegion> regions = Lists.newArrayList(region1, region2);
+
+    Configuration conf = HBaseConfiguration.create();
+    // Long period so the scheduled task never fires; we drive the aggregation 
manually.
+    conf.setLong(HConstants.REGIONSERVER_METRICS_PERIOD, 600 * 1000);
+
+    HRegionServer regionServer = mock(HRegionServer.class);
+    when(regionServer.getConfiguration()).thenReturn(conf);
+    when(regionServer.getOnlineRegionsLocalContext()).thenReturn(regions);
+
+    MetricsTableWrapperAggregateImpl wrapper = new 
MetricsTableWrapperAggregateImpl(regionServer);
+    try {
+      MetricsTableWrapperAggregateImpl.TableMetricsWrapperRunnable runnable =
+        wrapper.new TableMetricsWrapperRunnable();
+      runnable.run();
+
+      String table = TABLE.getNameAsString();
+      // avg = (10*2 + 20*3 + 4*5) / (2 + 3 + 5) = 100 / 10 = 10.
+      assertEquals(10, wrapper.getAvgStoreFileAge(table));
+      assertEquals(10, wrapper.getNumStoreFiles(table));
+      assertEquals(30, wrapper.getMaxStoreFileAge(table));
+      assertEquals(1, wrapper.getMinStoreFileAge(table));
+      assertEquals(3, wrapper.getNumStores(table));
+      assertEquals(2, wrapper.getNumRegions(table));
+    } finally {
+      wrapper.close();
+    }
+  }
+
+  private HRegion getMockedRegion(List<HStore> stores) {
+    TableDescriptor descriptor = mock(TableDescriptor.class);
+    when(descriptor.getTableName()).thenReturn(TABLE);
+    HRegion region = mock(HRegion.class);
+    when(region.getTableDescriptor()).thenReturn(descriptor);
+    when(region.getStores()).thenReturn(stores);
+    return region;
+  }
+
+  private HStore getMockedStore(String family, int storeFileCount, double 
avgStoreFileAge,
+    long maxStoreFileAge, long minStoreFileAge) {
+    HStore store = mock(HStore.class);
+    when(store.getColumnFamilyName()).thenReturn(family);
+    when(store.getStorefilesCount()).thenReturn(storeFileCount);
+    
when(store.getAvgStoreFileAge()).thenReturn(OptionalDouble.of(avgStoreFileAge));
+    
when(store.getMaxStoreFileAge()).thenReturn(OptionalLong.of(maxStoreFileAge));
+    
when(store.getMinStoreFileAge()).thenReturn(OptionalLong.of(minStoreFileAge));
+    when(store.getMemStoreSize()).thenReturn(mock(MemStoreSize.class));
+    return store;
+  }
+}

Reply via email to