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

yiguolei 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 a888597bf9c [opt](profile) Refine process of auto_profile for less 
memory usage (#48653)
a888597bf9c is described below

commit a888597bf9ce7be287adbf8d42d1036f519590ca
Author: zhiqiang <[email protected]>
AuthorDate: Thu Mar 6 18:29:30 2025 +0800

    [opt](profile) Refine process of auto_profile for less memory usage (#48653)
    
    ### What problem does this PR solve?
    
    In previous, auto_profile_threshold is calculated by background thread
    of ProfileManager.
    When FE has a high qps, this implementation makes profile in memory
    stacking until background thread wakes up.
    
    So, we move the calculation of auto_profile_threshold to
    Profile::update_summary.
---
 .../org/apache/doris/common/profile/Profile.java   |  59 ++++--------
 .../doris/common/profile/ProfileManager.java       |  78 +++++++--------
 .../doris/common/profile/RuntimeProfile.java       |   8 +-
 .../java/org/apache/doris/qe/QeProcessorImpl.java  |   8 +-
 .../doris/common/profile/AutoProfileTest.java      |  79 +++++++++++++++
 .../doris/common/profile/ProfileManagerTest.java   | 106 ++++++++++++++++++++-
 .../common/profile/ProfilePersistentTest.java      |   3 +
 .../common/profile/RuntimeProfileMergeTest.java    |   2 +
 8 files changed, 250 insertions(+), 93 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/Profile.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/Profile.java
index 0520aa3ef80..e15bafd6d0a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/profile/Profile.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/profile/Profile.java
@@ -105,7 +105,7 @@ public class Profile {
     private long queryFinishTimestamp = Long.MAX_VALUE;
     private Map<Integer, String> planNodeMap = Maps.newHashMap();
     private int profileLevel = MergedProfileLevel;
-    private long autoProfileDurationMs = -1;
+    protected long autoProfileDurationMs = -1;
     // Profile size is the size of profile file
     private long profileSize = 0;
 
@@ -264,7 +264,7 @@ public class Profile {
                 return;
             }
 
-            if (planner instanceof NereidsPlanner) {
+            if (planner != null && planner instanceof NereidsPlanner) {
                 NereidsPlanner nereidsPlanner = ((NereidsPlanner) planner);
                 physicalPlan = nereidsPlanner.getPhysicalPlan();
                 
physicalRelations.addAll(nereidsPlanner.getPhysicalRelations());
@@ -282,8 +282,21 @@ public class Profile {
             summaryProfile.update(summaryInfo);
 
             if (isFinished) {
-                this.markQueryFinished(System.currentTimeMillis());
+                this.markQueryFinished();
+                long durationMs = this.queryFinishTimestamp - 
summaryProfile.getQueryBeginTime();
+                // Duration ls less than autoProfileDuration, remove it from 
memory.
+                long durationThreshold = executionProfiles.isEmpty()
+                                    ? autoProfileDurationMs : 
executionProfiles.size() * autoProfileDurationMs;
+                if (this.queryFinishTimestamp != Long.MAX_VALUE && durationMs 
< durationThreshold) {
+                    ProfileManager.getInstance().removeProfile(this.getId());
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Removed profile {} because it's costs {} is 
less than {}", this.getId(),
+                                durationMs, autoProfileDurationMs * 
this.executionProfiles.size());
+                    }
+                    return;
+                }
             }
+
             // Nereids native insert not set planner, so it is null
             if (planner != null) {
                 this.planNodeMap = planner.getExplainStringMap();
@@ -432,40 +445,6 @@ public class Profile {
             return false;
         }
 
-        // below is the case where query has finished
-        boolean hasReportingProfile = false;
-
-        if (this.executionProfiles.isEmpty()) {
-            // Query finished, but no execution profile.
-            // 1. Query is executed on FE.
-            // 2. Not a SELECT query, just a DDL.
-            return false;
-        }
-
-        for (ExecutionProfile executionProfile : executionProfiles) {
-            if (!executionProfile.isCompleted()) {
-                hasReportingProfile = true;
-                break;
-            }
-        }
-
-        if (!hasReportingProfile) {
-            // query finished and no flying profile
-            // I do want to use TotalTime in summary profile, but it is an 
encoded string,
-            // it is hard to write a parse function.
-            long durationMs = this.queryFinishTimestamp - 
summaryProfile.getQueryBeginTime();
-            // time cost of this query is large enough.
-            if (this.queryFinishTimestamp != Long.MAX_VALUE && durationMs
-                    > (this.executionProfiles.size() * autoProfileDurationMs)) 
{
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug("Query/LoadJob {} costs {} ms, begin {} finish 
{}, need store its profile",
-                            getId(), durationMs, 
summaryProfile.getQueryBeginTime(), this.queryFinishTimestamp);
-                }
-                return true;
-            }
-            return false;
-        }
-
         if (this.queryFinishTimestamp == Long.MAX_VALUE) {
             LOG.warn("Logical error, query {} has finished, but 
queryFinishTimestamp is not set,", getId());
             return false;
@@ -473,8 +452,8 @@ public class Profile {
 
         long currentTimeMillis = System.currentTimeMillis();
         if (this.queryFinishTimestamp != Long.MAX_VALUE
-                    && (currentTimeMillis - this.queryFinishTimestamp)
-                        > Config.profile_waiting_time_for_spill_seconds * 
1000) {
+                && (currentTimeMillis - this.queryFinishTimestamp)
+                > Config.profile_waiting_time_for_spill_seconds * 1000) {
             LOG.warn("Profile {} should be stored to storage without waiting 
for incoming profile,"
                     + " since it has been waiting for {} ms, current time {} 
query finished time: {}",
                     getId(), currentTimeMillis - this.queryFinishTimestamp, 
currentTimeMillis,
@@ -500,7 +479,7 @@ public class Profile {
     }
 
     // Profile IO threads races with Coordinator threads.
-    public void markQueryFinished(long queryFinishTime) {
+    public void markQueryFinished() {
         try {
             if (this.profileHasBeenStored()) {
                 LOG.error("Logical error, profile {} has already been stored 
to storage", getId());
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileManager.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileManager.java
index 4600c93587b..5666ca8965a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileManager.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileManager.java
@@ -204,18 +204,22 @@ public class ProfileManager extends MasterDaemon {
             return;
         }
 
-        ProfileElement element = createElement(profile);
-        // 'insert into' does have job_id, put all profiles key with query_id
-        String key = profile.getSummaryProfile().getProfileId();
-        // check when push in, which can ensure every element in the list has 
QUERY_ID column,
-        // so there is no need to check when remove element from list.
-        if (Strings.isNullOrEmpty(key)) {
-            LOG.warn("the key or value of Map is null, "
-                    + "may be forget to insert 'QUERY_ID' or 'JOB_ID' column 
into infoStrings");
-        }
-
         writeLock.lock();
         try {
+            if (!queryIdToProfileMap.containsKey(profile.getId())) {
+                deleteOutdatedProfilesFromMemory(1);
+            }
+
+            ProfileElement element = createElement(profile);
+            // 'insert into' does have job_id, put all profiles key with 
query_id
+            String key = profile.getSummaryProfile().getProfileId();
+            // check when push in, which can ensure every element in the list 
has QUERY_ID column,
+            // so there is no need to check when remove element from list.
+            if (Strings.isNullOrEmpty(key)) {
+                LOG.warn("the key or value of Map is null, "
+                        + "may be forget to insert 'QUERY_ID' or 'JOB_ID' 
column into infoStrings");
+            }
+
             // a profile may be updated multiple times in queryIdToProfileMap,
             // and only needs to be inserted into the queryIdDeque for the 
first time.
             queryIdToProfileMap.put(key, element);
@@ -475,7 +479,6 @@ public class ProfileManager extends MasterDaemon {
         loadProfilesFromStorageIfFirstTime(false);
         writeProfileToStorage();
         deleteBrokenProfiles();
-        deleteOutdatedProfilesFromMemory();
         deleteOutdatedProfilesFromStorage();
         preventExecutionProfileLeakage();
     }
@@ -954,36 +957,12 @@ public class ProfileManager extends MasterDaemon {
         }
     }
 
-    protected void deleteOutdatedProfilesFromMemory() {
+    protected void deleteOutdatedProfilesFromMemory(int numOfNewProfiles) {
         StringBuilder stringBuilder = new StringBuilder();
-        StringBuilder stringBuilderTTL = new StringBuilder();
         writeLock.lock();
 
         try {
-            // Remove profiles that costs less than auto_profile_threshold_ms
-            List<String> profilesToRemove = Lists.newArrayList();
-
-            for (ProfileElement profileElement : 
this.queryIdToProfileMap.values()) {
-                if (profileElement.profile.shouldBeRemoveFromMemory()) {
-                    String profileId = 
profileElement.profile.getSummaryProfile().getProfileId();
-                    profilesToRemove.add(profileId);
-                    stringBuilder.append(profileId).append(",");
-                    if (LOG.isDebugEnabled()) {
-                        LOG.debug("Profile {} should be filtered from memory, 
information {}", profileId,
-                                profileElement.profile.debugInfo());
-                    }
-                }
-            }
-
-            for (String profileId : profilesToRemove) {
-                ProfileElement profileElement = 
queryIdToProfileMap.get(profileId);
-                queryIdToProfileMap.remove(profileId);
-                for (ExecutionProfile executionProfile : 
profileElement.profile.getExecutionProfiles()) {
-                    
queryIdToExecutionProfiles.remove(executionProfile.getQueryId());
-                }
-            }
-
-            if (this.queryIdToProfileMap.size() <= 
Config.max_query_profile_num) {
+            if (this.queryIdToProfileMap.size() + numOfNewProfiles <= 
Config.max_query_profile_num) {
                 return;
             }
 
@@ -992,10 +971,10 @@ public class ProfileManager extends MasterDaemon {
             // query finished time of unfinished query is INT_MAX, so they 
will be on the bottom of the heap.
             PriorityQueue<ProfileElement> queueIdDeque = 
getProfileOrderByQueryFinishTime();
 
-            while (queueIdDeque.size() > Config.max_query_profile_num && 
!queueIdDeque.isEmpty()) {
+            while (queueIdDeque.size() + numOfNewProfiles > 
Config.max_query_profile_num && !queueIdDeque.isEmpty()) {
                 ProfileElement profileElement = queueIdDeque.poll();
                 String profileId = 
profileElement.profile.getSummaryProfile().getProfileId();
-                stringBuilderTTL.append(profileId).append(",");
+                stringBuilder.append(profileId).append(",");
                 queryIdToProfileMap.remove(profileId);
                 for (ExecutionProfile executionProfile : 
profileElement.profile.getExecutionProfiles()) {
                     
queryIdToExecutionProfiles.remove(executionProfile.getQueryId());
@@ -1010,10 +989,9 @@ public class ProfileManager extends MasterDaemon {
             int profileNum = queryIdToProfileMap.size();
             writeLock.unlock();
 
-            if (stringBuilder.length() != 0 || stringBuilderTTL.length() != 0) 
{
-                LOG.info("Filtered profiles {}, outdated profiles {}, they are 
removed from memory,"
-                                + " current profile map size {}",
-                        stringBuilder.toString(), stringBuilderTTL.toString(), 
profileNum);
+            if (stringBuilder.length() != 0) {
+                LOG.info("Outdated profiles {}, they are removed from memory, 
current profile map size {}",
+                        stringBuilder.toString(), profileNum);
             }
         }
     }
@@ -1064,4 +1042,18 @@ public class ProfileManager extends MasterDaemon {
             isProfileLoadedLock.readLock().unlock();
         }
     }
+
+    public void removeProfile(String profileId) {
+        writeLock.lock();
+        try {
+            ProfileElement profileToRemove = 
this.queryIdToProfileMap.remove(profileId);
+            if (profileToRemove != null) {
+                for (ExecutionProfile executionProfile : 
profileToRemove.profile.getExecutionProfiles()) {
+                    
queryIdToExecutionProfiles.remove(executionProfile.getQueryId());
+                }
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/RuntimeProfile.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/RuntimeProfile.java
index d3321d7de6c..c607dc570d0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/profile/RuntimeProfile.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/profile/RuntimeProfile.java
@@ -172,10 +172,6 @@ public class RuntimeProfile {
         return this.nodeid;
     }
 
-    public Boolean sinkOperator() {
-        return this.isSinkOperator;
-    }
-
     public Map<String, Counter> getCounterMap() {
         return counterMap;
     }
@@ -196,9 +192,7 @@ public class RuntimeProfile {
         return childCounterMap;
     }
 
-    public double getLocalTimePercent() {
-        return localTimePercent;
-    }
+
 
     public Counter addCounter(String name, TUnit type, String 
parentCounterName) {
         counterLock.writeLock().lock();
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/QeProcessorImpl.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/QeProcessorImpl.java
index 378d37d082f..275dc234706 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/QeProcessorImpl.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/QeProcessorImpl.java
@@ -75,8 +75,12 @@ public final class QeProcessorImpl implements QeProcessor {
     private Status processQueryProfile(TQueryProfile profile, TNetworkAddress 
address, boolean isDone) {
         ExecutionProfile executionProfile = 
ProfileManager.getInstance().getExecutionProfile(profile.query_id);
         if (executionProfile == null) {
-            LOG.warn("Could not find execution profile, query {} be {}",
-                                DebugUtil.printId(profile.query_id), 
address.toString());
+            // When auto_profile_threshold_ms is not -1, this branch will be 
very common.
+            // So this log is set to debug level.
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Could not find execution profile, query {} be {}",
+                        DebugUtil.printId(profile.query_id), 
address.toString());
+            }
             return new Status(TStatusCode.NOT_FOUND, "Could not find execution 
profile with query id "
                     + DebugUtil.printId(profile.query_id));
         }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/AutoProfileTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/AutoProfileTest.java
new file mode 100644
index 00000000000..5475cfc4c98
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/AutoProfileTest.java
@@ -0,0 +1,79 @@
+// 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.doris.common.profile;
+
+import org.apache.doris.common.util.DebugUtil;
+import org.apache.doris.thrift.TUniqueId;
+
+import mockit.Expectations;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.parallel.ResourceLock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+@ResourceLock("global")
+public class AutoProfileTest {
+    @BeforeAll
+    static void setUp() {
+        ProfileManager.getInstance().cleanProfile();
+    }
+
+    private Profile createProfile() {
+        UUID taskId = UUID.randomUUID();
+        TUniqueId queryId = new TUniqueId(taskId.getMostSignificantBits(), 
taskId.getLeastSignificantBits());
+        List<Integer> fragments = new ArrayList<>();
+        ExecutionProfile executionProfile = new ExecutionProfile(queryId, 
fragments);
+
+        Profile profile = 
ProfileManagerTest.constructProfile(DebugUtil.printId(queryId));
+        profile.addExecutionProfile(executionProfile);
+        return profile;
+    }
+
+    @Test
+    public void testAutoProfile() throws InterruptedException {
+        Profile profile = createProfile();
+        SummaryProfile summaryProfile = new SummaryProfile();
+        profile.setSummaryProfile(summaryProfile);
+        Map<String, String> summaryInfo = new HashMap<>();
+
+        new Expectations(summaryProfile) {
+            {
+                summaryProfile.update(summaryInfo);
+                summaryProfile.getQueryBeginTime();
+                result = System.currentTimeMillis();
+            }
+        };
+        profile.autoProfileDurationMs = 1000;
+        Thread.sleep(899);
+        profile.updateSummary(summaryInfo, true, null);
+        
Assertions.assertNull(ProfileManager.getInstance().queryIdToProfileMap.get(profile.getId()));
+
+        profile = createProfile();
+        profile.setSummaryProfile(summaryProfile);
+        profile.autoProfileDurationMs = 500;
+        Thread.sleep(899);
+        profile.updateSummary(summaryInfo, true, null);
+        
Assertions.assertNotNull(ProfileManager.getInstance().queryIdToProfileMap.get(profile.getId()));
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfileManagerTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfileManagerTest.java
index d7fa81e9b78..21096556a8f 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfileManagerTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfileManagerTest.java
@@ -32,6 +32,7 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
 
 import java.io.File;
 import java.io.IOException;
@@ -45,12 +46,14 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+@ResourceLock("global")
 class ProfileManagerTest {
     private static final Logger LOG = 
LogManager.getLogger(ProfilePersistentTest.class);
 
     private static ProfileManager profileManager;
     private File tempDir;
     private String originalPath;
+    private int originMaxProfiles;
 
     @BeforeAll
     static void setUp() throws Exception {
@@ -64,12 +67,14 @@ class ProfileManagerTest {
         ProfileManager.PROFILE_STORAGE_PATH = tempDir.getAbsolutePath();
         profileManager.cleanProfile();
         profileManager.isProfileLoaded = false;
+        originMaxProfiles = Config.max_query_profile_num;
     }
 
     @AfterEach
     void cleanup() {
         ProfileManager.PROFILE_STORAGE_PATH = originalPath;
         FileUtils.deleteQuietly(tempDir);
+        Config.max_query_profile_num = originMaxProfiles;
     }
 
     @Test
@@ -731,7 +736,7 @@ class ProfileManagerTest {
         }
 
         // Trigger cleanup
-        profileManager.deleteOutdatedProfilesFromMemory();
+        profileManager.deleteOutdatedProfilesFromMemory(0);
 
         // Verify memory profile count is within limit
         Assertions.assertEquals(Config.max_query_profile_num, 
profileManager.queryIdToProfileMap.size());
@@ -741,4 +746,103 @@ class ProfileManagerTest {
             
Assertions.assertTrue(profileManager.queryIdToProfileMap.containsKey(profileId));
         }
     }
+
+    @Test
+    public void testDeleteOutdatedProfilesWhenExceedLimit() {
+        List<Profile> profiles = new ArrayList<>();
+
+        Config.max_query_profile_num = 3;
+        for (int i = 0; i < 5; i++) {
+            UUID taskId = UUID.randomUUID();
+            TUniqueId queryId = new TUniqueId(taskId.getMostSignificantBits(), 
taskId.getLeastSignificantBits());
+            String profileId = DebugUtil.printId(queryId);
+            Profile profile = constructProfile(profileId);
+            profile.setQueryFinishTimestamp(System.currentTimeMillis() + i * 
1000); // Different finish times
+            profiles.add(profile);
+        }
+        for (int i = 0; i < 3; i++) {
+            Profile profile = profiles.get(i);
+            profileManager.pushProfile(profile);
+        }
+        // Verify profile count
+        Assertions.assertEquals(3, profileManager.queryIdToProfileMap.size());
+
+        // Try to delete outdated profiles
+        profileManager.deleteOutdatedProfilesFromMemory(0);
+
+        // Verify no profiles were deleted
+        Assertions.assertEquals(3, profileManager.queryIdToProfileMap.size());
+
+        for (int i = 3; i < 5; i++) {
+            Profile profile = profiles.get(i);
+            profileManager.pushProfile(profile);
+        }
+
+        for (int i = 0; i < 5; i++) {
+            Profile profile = profiles.get(i);
+            if (i <= 1) {
+                
Assertions.assertFalse(profileManager.queryIdToProfileMap.containsKey(profile.getId()));
+            } else {
+                
Assertions.assertTrue(profileManager.queryIdToProfileMap.containsKey(profile.getId()));
+            }
+        }
+
+        profiles.clear();
+
+        Assertions.assertEquals(3, profileManager.queryIdToProfileMap.size());
+        for (Profile profile : profiles) {
+            
Assertions.assertTrue(profileManager.queryIdToProfileMap.containsKey(profile.getId()));
+        }
+    }
+
+    @Test
+    public void testUnfinishedProfilesNotDeleted() {
+        // Create an unfinished profile (finish time = Long.MAX_VALUE)
+        List<Profile> profileUnfinished = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            UUID taskId = UUID.randomUUID();
+            TUniqueId queryId = new TUniqueId(taskId.getMostSignificantBits(), 
taskId.getLeastSignificantBits());
+            String profileId = DebugUtil.printId(queryId);
+            Profile profile = constructProfile(profileId);
+            profileUnfinished.add(profile);
+            profileManager.pushProfile(profile);
+        }
+
+        List<Profile> profileFinished = new ArrayList<>();
+        for (int i = 0; i < 3; i++) {
+            UUID taskId = UUID.randomUUID();
+            TUniqueId queryId = new TUniqueId(taskId.getMostSignificantBits(), 
taskId.getLeastSignificantBits());
+            String profileId = DebugUtil.printId(queryId);
+            Profile profile = constructProfile(profileId);
+            profile.setQueryFinishTimestamp(System.currentTimeMillis() + i * 
1000); // Different finish times
+            profileFinished.add(profile);
+            profileManager.pushProfile(profile);
+        }
+
+        // Try to delete outdated profiles
+        profileManager.deleteOutdatedProfilesFromMemory(0);
+
+        // Verify unfinished profile was not deleted
+        for (Profile profile : profileUnfinished) {
+            
Assertions.assertTrue(profileManager.queryIdToProfileMap.containsKey(profile.getId()));
+        }
+
+        Assertions.assertEquals(5, profileManager.queryIdToProfileMap.size());
+
+        profileFinished.clear();
+        for (int i = 0; i < 5; i++) {
+            UUID taskId = UUID.randomUUID();
+            TUniqueId queryId = new TUniqueId(taskId.getMostSignificantBits(), 
taskId.getLeastSignificantBits());
+            String profileId = DebugUtil.printId(queryId);
+            Profile profile = constructProfile(profileId);
+            profile.setQueryFinishTimestamp(System.currentTimeMillis() + i * 
1000); // Different finish times
+            profileFinished.add(profile);
+            profileManager.pushProfile(profile);
+        }
+
+        // Verify unfinished profile was not deleted
+        for (Profile profile : profileUnfinished) {
+            
Assertions.assertTrue(profileManager.queryIdToProfileMap.containsKey(profile.getId()));
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfilePersistentTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfilePersistentTest.java
index d1091e24cb8..a647103c989 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfilePersistentTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/ProfilePersistentTest.java
@@ -30,6 +30,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -51,6 +52,8 @@ import java.util.UUID;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
+@ResourceLock("global")
+
 public class ProfilePersistentTest {
     private static final Logger LOG = 
LogManager.getLogger(ProfilePersistentTest.class);
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/RuntimeProfileMergeTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/RuntimeProfileMergeTest.java
index 10b03155523..4d2cf9c9003 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/common/profile/RuntimeProfileMergeTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/common/profile/RuntimeProfileMergeTest.java
@@ -28,11 +28,13 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.jupiter.api.parallel.ResourceLock;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Set;
 
+@ResourceLock("global")
 public class RuntimeProfileMergeTest {
     private static final Logger LOG = 
LogManager.getLogger(RuntimeProfileMergeTest.class);
 


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

Reply via email to