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]