From 21b8887b543c3e950479bdfd4e209498ef33c30c Mon Sep 17 00:00:00 2001 From: zhiqiang Date: Fri, 27 Sep 2024 09:55:43 +0800 Subject: [PATCH] [feat](profile) Print changed session var in profile #41016 (#41317) cherry pick from #41016 --- .../apache/doris/common/profile/Profile.java | 17 +++++- .../apache/doris/common/util/DebugUtil.java | 59 +++++++++++++++++++ .../org/apache/doris/qe/StmtExecutor.java | 2 + .../java/org/apache/doris/qe/VariableMgr.java | 36 +++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) 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 b9cefdd0c4..f92cf5cb93 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 @@ -59,8 +59,8 @@ public class Profile { private List executionProfiles = Lists.newArrayList(); private boolean isFinished; private Map planNodeMap; - private int profileLevel = 3; + private String changedSessionVarCache = ""; public Profile(String name, boolean isEnable, int profileLevel, boolean isPipelineX) { this.name = name; @@ -122,6 +122,7 @@ public class Profile { // add summary to builder summaryProfile.prettyPrint(builder); waitProfileCompleteIfNeeded(); + getChangedSessionVars(builder); // Only generate merged profile for select, insert into select. // Not support broker load now. if (this.profileLevel == MergedProfileLevel && this.executionProfiles.size() == 1) { @@ -186,4 +187,18 @@ public class Profile { Gson gson = new GsonBuilder().setPrettyPrinting().create(); return gson.toJson(rootProfile.toBrief()); } + + public void setChangedSessionVar(String changedSessionVar) { + this.changedSessionVarCache = changedSessionVar; + } + + private void getChangedSessionVars(StringBuilder builder) { + if (builder == null) { + builder = new StringBuilder(); + } + + builder.append("\nChanged Session Variables:\n"); + builder.append(changedSessionVarCache); + builder.append("\n"); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java index 2a52420a96..287f35f32a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/DebugUtil.java @@ -26,6 +26,7 @@ import com.google.common.base.Strings; import java.io.PrintWriter; import java.io.StringWriter; import java.text.DecimalFormat; +import java.util.List; import java.util.UUID; public class DebugUtil { @@ -177,4 +178,62 @@ public class DebugUtil { e.printStackTrace(new PrintWriter(sw)); return sw.toString(); } + + public static String prettyPrintChangedSessionVar(List> nestedList) { + if (nestedList == null || nestedList.isEmpty()) { + return ""; + } + + StringBuilder output = new StringBuilder(); + + // Assuming each inner list has exactly 3 columns + int[] columnWidths = new int[3]; + + // Calculate the maximum width of each column + // First consider the header widths: "VarName", "CurrentValue", "DefaultValue" + String[] headers = {"VarName", "CurrentValue", "DefaultValue"}; + for (int i = 0; i < headers.length; i++) { + columnWidths[i] = headers[i].length(); // Initialize with header length + } + + // Update column widths based on data + for (List row : nestedList) { + for (int i = 0; i < row.size(); i++) { + columnWidths[i] = Math.max(columnWidths[i], row.get(i).length()); + } + } + + // Build the table header + for (int i = 0; i < headers.length; i++) { + output.append(String.format("%-" + columnWidths[i] + "s", headers[i])); + if (i < headers.length - 1) { + output.append(" | "); // Separator between columns + } + } + output.append("\n"); // Newline after the header + + // Add a separator line for better readability (optional) + for (int i = 0; i < headers.length; i++) { + output.append(String.format("%-" + columnWidths[i] + "s", Strings.repeat("-", columnWidths[i]))); + if (i < headers.length - 1) { + output.append("-|-"); // Separator between columns + } + } + output.append("\n"); // Newline after the separator + + // Build the table body with proper alignment based on column widths + for (List row : nestedList) { + for (int i = 0; i < row.size(); i++) { + String element = row.get(i); + // Pad with spaces if the element is shorter than the column width + output.append(String.format("%-" + columnWidths[i] + "s", element)); + if (i < row.size() - 1) { + output.append(" | "); // Separator between columns + } + } + output.append("\n"); // Newline after each row + } + + return output.toString(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 8d59f49b0c..24a9a98814 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -648,6 +648,8 @@ public class StmtExecutor { context.setQueryId(queryId); context.setStartTime(); profile.getSummaryProfile().setQueryBeginTime(); + List> changedSessionVar = VariableMgr.dumpChangedVars(context.getSessionVariable()); + profile.setChangedSessionVar(DebugUtil.prettyPrintChangedSessionVar(changedSessionVar)); context.setStmtId(STMT_ID_GENERATOR.incrementAndGet()); parseByNereids(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java index 38a8b5239d..3515e9e086 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/VariableMgr.java @@ -795,6 +795,42 @@ public class VariableMgr { return changedRows; } + public static List> dumpChangedVars(SessionVariable sessionVar) { + // Hold the read lock when session dump, because this option need to access global variable. + rlock.lock(); + List> changedRows = Lists.newArrayList(); + try { + for (Map.Entry entry : ctxByDisplayVarName.entrySet()) { + VarContext ctx = entry.getValue(); + List row = Lists.newArrayList(); + String varName = entry.getKey(); + String curValue = getValue(sessionVar, ctx.getField()); + String defaultValue = ctx.getDefaultValue(); + if (VariableVarConverters.hasConverter(varName)) { + try { + defaultValue = VariableVarConverters.decode(varName, Long.valueOf(defaultValue)); + curValue = VariableVarConverters.decode(varName, Long.valueOf(curValue)); + } catch (DdlException e) { + LOG.warn("Decode session variable {} failed, reason: {}", varName, e.getMessage()); + } + } + + if (curValue.equals(defaultValue)) { + continue; + } + + row.add(varName); + row.add(curValue); + row.add(defaultValue); + changedRows.add(row); + } + } finally { + rlock.unlock(); + } + + return changedRows; + } + @Retention(RetentionPolicy.RUNTIME) public @interface VarAttr { // Name in show variables and set statement;