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

hello-stephen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new ab3ac86e7c7 [fix](fe) Avoid eager allocations in cloud tablet indexes 
(#66378)
ab3ac86e7c7 is described below

commit ab3ac86e7c7f30ac18625c13589b3df02aa8c1f4
Author: deardeng <[email protected]>
AuthorDate: Tue Aug 4 10:18:47 2026 +0800

    [fix](fe) Avoid eager allocations in cloud tablet indexes (#66378)
    
    Problem Summary: Cloud tablet route-cache rebuilding calls
    fillBeToTablets for current and future placements. The previous
    putIfAbsent calls eagerly constructed up to six candidate maps and sets
    for every placement even when the keys already existed, and then
    performed separate lookups. Use the containers returned by
    computeIfAbsent at every level and add a focused unit test that verifies
    all six container paths while preserving the global, table, and
    partition index contents.
    
    An isomorphic multi-scale JVM allocation model with 2 million entities,
    four-route fan-out, current/future passes, and three index scopes
    estimated cumulative allocation per modeled rebuild at 12.52 GiB before
    and 8.59 GiB after the change, saving 3.93 GiB (31.4%). For 4 million
    tablets, the fill-path cumulative-allocation reduction is expected to
    remain about 31% under comparable topology, while the absolute GiB
    saving depends on cluster and replica fan-out. The retained graph
    remained about 3.76 GiB and the peak proxy about 966 MiB, so this change
    does not claim a comparable steady-state heap or process-wide reduction.
    Timing samples were noisy, so no throughput improvement is claimed.
---
 .../doris/cloud/catalog/CloudTabletRebalancer.java | 21 +++----
 .../cloud/catalog/CloudTabletRebalancerTest.java   | 69 ++++++++++++++++++++++
 2 files changed, 78 insertions(+), 12 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
index 6acaad24e07..1a231170b9e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudTabletRebalancer.java
@@ -1059,22 +1059,19 @@ public class CloudTabletRebalancer extends MasterDaemon 
{
                                 ConcurrentHashMap<Long, 
ConcurrentHashMap<Long, ConcurrentHashMap<Long, Set<Long>>>>
                                     partToTablets) {
         // global
-        globalBeToTablets.putIfAbsent(be, ConcurrentHashMap.newKeySet());
-        globalBeToTablets.get(be).add(tabletId);
+        globalBeToTablets.computeIfAbsent(be, ignored -> 
ConcurrentHashMap.newKeySet()).add(tabletId);
 
         // table
-        beToTabletsInTable.putIfAbsent(tableId, new ConcurrentHashMap<Long, 
Set<Long>>());
-        ConcurrentHashMap<Long, Set<Long>> beToTabletsOfTable = 
beToTabletsInTable.get(tableId);
-        beToTabletsOfTable.putIfAbsent(be, ConcurrentHashMap.newKeySet());
-        beToTabletsOfTable.get(be).add(tabletId);
+        ConcurrentHashMap<Long, Set<Long>> beToTabletsOfTable =
+                beToTabletsInTable.computeIfAbsent(tableId, ignored -> new 
ConcurrentHashMap<>());
+        beToTabletsOfTable.computeIfAbsent(be, ignored -> 
ConcurrentHashMap.newKeySet()).add(tabletId);
 
         // partition
-        partToTablets.putIfAbsent(partId, new ConcurrentHashMap<Long, 
ConcurrentHashMap<Long, Set<Long>>>());
-        ConcurrentHashMap<Long, ConcurrentHashMap<Long, Set<Long>>> 
indexToTablets = partToTablets.get(partId);
-        indexToTablets.putIfAbsent(indexId, new ConcurrentHashMap<Long, 
Set<Long>>());
-        ConcurrentHashMap<Long, Set<Long>> beToTabletsOfIndex = 
indexToTablets.get(indexId);
-        beToTabletsOfIndex.putIfAbsent(be, ConcurrentHashMap.newKeySet());
-        beToTabletsOfIndex.get(be).add(tabletId);
+        ConcurrentHashMap<Long, ConcurrentHashMap<Long, Set<Long>>> 
indexToTablets =
+                partToTablets.computeIfAbsent(partId, ignored -> new 
ConcurrentHashMap<>());
+        ConcurrentHashMap<Long, Set<Long>> beToTabletsOfIndex =
+                indexToTablets.computeIfAbsent(indexId, ignored -> new 
ConcurrentHashMap<>());
+        beToTabletsOfIndex.computeIfAbsent(be, ignored -> 
ConcurrentHashMap.newKeySet()).add(tabletId);
     }
 
     private void enqueueWarmupTask(WarmupTabletTask task) {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerTest.java
index 8637be3c76a..080ee4f5a34 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/cloud/catalog/CloudTabletRebalancerTest.java
@@ -41,6 +41,7 @@ import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
 
 public class CloudTabletRebalancerTest {
 
@@ -81,6 +82,30 @@ public class CloudTabletRebalancerTest {
         }
     }
 
+    private static class CountingConcurrentHashMap<K, V> extends 
ConcurrentHashMap<K, V> {
+        private int computeIfAbsentCalls;
+        private int getCalls;
+        private int putIfAbsentCalls;
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> 
mappingFunction) {
+            computeIfAbsentCalls++;
+            return super.computeIfAbsent(key, mappingFunction);
+        }
+
+        @Override
+        public V get(Object key) {
+            getCalls++;
+            return super.get(key);
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            putIfAbsentCalls++;
+            return super.putIfAbsent(key, value);
+        }
+    }
+
     private static void setField(Object obj, String name, Object value) throws 
Exception {
         Field f = CloudTabletRebalancer.class.getDeclaredField(name);
         f.setAccessible(true);
@@ -101,6 +126,50 @@ public class CloudTabletRebalancerTest {
         return (T) m.invoke(obj, args);
     }
 
+    @Test
+    public void testFillBeToTabletsUsesComputedContainers() {
+        TestRebalancer rebalancer = new TestRebalancer();
+        long beId = 1L;
+        long tableId = 2L;
+        long partitionId = 3L;
+        long indexId = 4L;
+
+        CountingConcurrentHashMap<Long, Set<Long>> globalBeToTablets = new 
CountingConcurrentHashMap<>();
+        CountingConcurrentHashMap<Long, ConcurrentHashMap<Long, Set<Long>>> 
beToTabletsInTable =
+                new CountingConcurrentHashMap<>();
+        CountingConcurrentHashMap<Long, Set<Long>> beToTabletsOfTable = new 
CountingConcurrentHashMap<>();
+        beToTabletsInTable.put(tableId, beToTabletsOfTable);
+
+        CountingConcurrentHashMap<Long, ConcurrentHashMap<Long, 
ConcurrentHashMap<Long, Set<Long>>>>
+                partToTablets = new CountingConcurrentHashMap<>();
+        CountingConcurrentHashMap<Long, ConcurrentHashMap<Long, Set<Long>>> 
indexToTablets =
+                new CountingConcurrentHashMap<>();
+        CountingConcurrentHashMap<Long, Set<Long>> beToTabletsOfIndex = new 
CountingConcurrentHashMap<>();
+        partToTablets.put(partitionId, indexToTablets);
+        indexToTablets.put(indexId, beToTabletsOfIndex);
+
+        rebalancer.fillBeToTablets(beId, tableId, partitionId, indexId, 5L,
+                globalBeToTablets, beToTabletsInTable, partToTablets);
+        rebalancer.fillBeToTablets(beId, tableId, partitionId, indexId, 6L,
+                globalBeToTablets, beToTabletsInTable, partToTablets);
+
+        assertComputedContainerUsed(globalBeToTablets);
+        assertComputedContainerUsed(beToTabletsInTable);
+        assertComputedContainerUsed(beToTabletsOfTable);
+        assertComputedContainerUsed(partToTablets);
+        assertComputedContainerUsed(indexToTablets);
+        assertComputedContainerUsed(beToTabletsOfIndex);
+        Assertions.assertEquals(Set.of(5L, 6L), globalBeToTablets.get(beId));
+        Assertions.assertEquals(Set.of(5L, 6L), beToTabletsOfTable.get(beId));
+        Assertions.assertEquals(Set.of(5L, 6L), beToTabletsOfIndex.get(beId));
+    }
+
+    private static void 
assertComputedContainerUsed(CountingConcurrentHashMap<?, ?> map) {
+        Assertions.assertEquals(2, map.computeIfAbsentCalls);
+        Assertions.assertEquals(0, map.putIfAbsentCalls);
+        Assertions.assertEquals(0, map.getCalls);
+    }
+
     @Test
     public void testPickTabletPreferCold_picksColdWhenAvailable() throws 
Exception {
         TestRebalancer r = new TestRebalancer();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to