[feature](config) support "experimental" prefix for FE config (#18699)
For each release of Doris, there are some experimental features. These feature may not stable or qualified enough, and user need to use it by setting config or session variables, eg, set enable_mtmv = true, otherwise, these feature is disable by default. We should explicitly tell user which features are experimental, so that user will notice that and decide whether to use it. Changes In this PR, I support the experimental_ prefix for FE config and session variables. Session Variable Given enable_nereids_planner as an example. The Nereids planner is an experimental feature in Doris, so there is an EXPERIMENTAL annotation for it: @VariableMgr.VarAttr(..., expType = ExperimentalType.EXPERIMENTAL) private boolean enableNereidsPlanner = false; And for compatibility, user can set it by: set enable_nereids_planner = true; set experimental_enable_nereids_planner = true; And for show variables, it will only show experimental_enable_nereids_planner entry. And you can also see all experimental session variables by: show variables like "%experimental%" Config Same as session variable, give enable_mtmv as an example. @ConfField(..., expType = ExperimentalType.EXPERIMENTAL) public static boolean enable_mtmv = false; User can set it in fe.conf or ADMIN SET FRONTEND CONFIG stmt with both names: enable_mtmv experimental_enable_mtmv And user can see all experimental FE configs by: ADMIN SHOW FRONTEND CONFIG LIKE "%experimental%"; TODO Support this feature for BE config Only add experimental for: enable_pipeline_engine enable_nereids_planner enable_single_replica_insert and FE config: enable_mtmv enabel_ssl enable_fqdn_mode Should modify other config and session vars
This commit is contained in:
@ -21,6 +21,7 @@ import org.apache.doris.analysis.SetVar;
|
||||
import org.apache.doris.analysis.StringLiteral;
|
||||
import org.apache.doris.common.Config;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.common.ExperimentalUtil.ExperimentalType;
|
||||
import org.apache.doris.common.io.Text;
|
||||
import org.apache.doris.common.io.Writable;
|
||||
import org.apache.doris.common.util.TimeUtils;
|
||||
@ -459,7 +460,7 @@ public class SessionVariable implements Serializable, Writable {
|
||||
@VariableMgr.VarAttr(name = ENABLE_COLOCATE_SCAN)
|
||||
public boolean enableColocateScan = false;
|
||||
|
||||
@VariableMgr.VarAttr(name = ENABLE_BUCKET_SHUFFLE_JOIN)
|
||||
@VariableMgr.VarAttr(name = ENABLE_BUCKET_SHUFFLE_JOIN, expType = ExperimentalType.EXPERIMENTAL_ONLINE)
|
||||
public boolean enableBucketShuffleJoin = true;
|
||||
|
||||
@VariableMgr.VarAttr(name = PREFER_JOIN_METHOD)
|
||||
@ -529,7 +530,7 @@ public class SessionVariable implements Serializable, Writable {
|
||||
public boolean extractWideRangeExpr = true;
|
||||
|
||||
|
||||
@VariableMgr.VarAttr(name = ENABLE_PIPELINE_ENGINE, fuzzy = true)
|
||||
@VariableMgr.VarAttr(name = ENABLE_PIPELINE_ENGINE, fuzzy = true, expType = ExperimentalType.EXPERIMENTAL)
|
||||
public boolean enablePipelineEngine = false;
|
||||
|
||||
@VariableMgr.VarAttr(name = ENABLE_PARALLEL_OUTFILE)
|
||||
@ -620,7 +621,7 @@ public class SessionVariable implements Serializable, Writable {
|
||||
* the new optimizer is fully developed. I hope that day
|
||||
* would be coming soon.
|
||||
*/
|
||||
@VariableMgr.VarAttr(name = ENABLE_NEREIDS_PLANNER, needForward = true)
|
||||
@VariableMgr.VarAttr(name = ENABLE_NEREIDS_PLANNER, needForward = true, expType = ExperimentalType.EXPERIMENTAL)
|
||||
private boolean enableNereidsPlanner = false;
|
||||
|
||||
@VariableMgr.VarAttr(name = DISABLE_NEREIDS_RULES, needForward = true)
|
||||
@ -661,7 +662,8 @@ public class SessionVariable implements Serializable, Writable {
|
||||
@VariableMgr.VarAttr(name = SESSION_CONTEXT, needForward = true)
|
||||
public String sessionContext = "";
|
||||
|
||||
@VariableMgr.VarAttr(name = ENABLE_SINGLE_REPLICA_INSERT, needForward = true)
|
||||
@VariableMgr.VarAttr(name = ENABLE_SINGLE_REPLICA_INSERT,
|
||||
needForward = true, expType = ExperimentalType.EXPERIMENTAL)
|
||||
public boolean enableSingleReplicaInsert = false;
|
||||
|
||||
@VariableMgr.VarAttr(name = ENABLE_FUNCTION_PUSHDOWN)
|
||||
@ -743,7 +745,6 @@ public class SessionVariable implements Serializable, Writable {
|
||||
public boolean enableUnicodeNameSupport = false;
|
||||
|
||||
@VariableMgr.VarAttr(name = REPEAT_MAX_NUM, needForward = true)
|
||||
|
||||
public int repeatMaxNum = 10000;
|
||||
|
||||
@VariableMgr.VarAttr(name = GROUP_CONCAT_MAX_LEN)
|
||||
@ -1922,7 +1923,22 @@ public class SessionVariable implements Serializable, Writable {
|
||||
return;
|
||||
}
|
||||
setIsSingleSetVar(true);
|
||||
VariableMgr.setVar(this,
|
||||
new SetVar(SessionVariable.ENABLE_NEREIDS_PLANNER, new StringLiteral("false")));
|
||||
VariableMgr.setVar(this, new SetVar(SessionVariable.ENABLE_NEREIDS_PLANNER, new StringLiteral("false")));
|
||||
}
|
||||
|
||||
// return number of variables by given experimental type
|
||||
public int getVariableNumByExperimentalType(ExperimentalType type) {
|
||||
int num = 0;
|
||||
Field[] fields = SessionVariable.class.getDeclaredFields();
|
||||
for (Field f : fields) {
|
||||
VarAttr varAttr = f.getAnnotation(VarAttr.class);
|
||||
if (varAttr == null) {
|
||||
continue;
|
||||
}
|
||||
if (varAttr.expType() == type) {
|
||||
++num;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,8 @@ import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.common.DdlException;
|
||||
import org.apache.doris.common.ErrorCode;
|
||||
import org.apache.doris.common.ErrorReport;
|
||||
import org.apache.doris.common.ExperimentalUtil;
|
||||
import org.apache.doris.common.ExperimentalUtil.ExperimentalType;
|
||||
import org.apache.doris.common.PatternMatcher;
|
||||
import org.apache.doris.nereids.trees.expressions.literal.Literal;
|
||||
import org.apache.doris.persist.GlobalVarPersistInfo;
|
||||
@ -34,6 +36,7 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.commons.lang.SerializationUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -108,6 +111,10 @@ public class VariableMgr {
|
||||
// Map variable name to variable context which have enough information to change variable value.
|
||||
// This map contains info of all session and global variables.
|
||||
private static ImmutableMap<String, VarContext> ctxByVarName;
|
||||
// Built from ctxByVarName.
|
||||
// If a session variable "foo" is an experimental variable,
|
||||
// its display name is "experimental_foo"
|
||||
private static ImmutableMap<String, VarContext> ctxByDisplayVarName;
|
||||
|
||||
// This variable is equivalent to the default value of session variables.
|
||||
// Whenever a new session is established, the value in this object is copied to the session-level variable.
|
||||
@ -131,6 +138,7 @@ public class VariableMgr {
|
||||
defaultSessionVariable = new SessionVariable();
|
||||
ImmutableSortedMap.Builder<String, VarContext> builder = getStringVarContextBuilder(defaultSessionVariable);
|
||||
ctxByVarName = builder.build();
|
||||
ctxByDisplayVarName = getDisplaySessionVars();
|
||||
}
|
||||
|
||||
public static SessionVariable getDefaultSessionVariable() {
|
||||
@ -243,10 +251,20 @@ public class VariableMgr {
|
||||
// setVar: variable information that needs to be set
|
||||
public static void setVar(SessionVariable sessionVariable, SetVar setVar)
|
||||
throws DdlException {
|
||||
VarContext ctx = ctxByVarName.get(setVar.getVariable());
|
||||
String varName = setVar.getVariable();
|
||||
boolean hasExpPrefix = false;
|
||||
if (varName.startsWith(ExperimentalUtil.EXPERIMENTAL_PREFIX)) {
|
||||
varName = varName.substring(ExperimentalUtil.EXPERIMENTAL_PREFIX.length());
|
||||
hasExpPrefix = true;
|
||||
}
|
||||
VarContext ctx = ctxByVarName.get(varName);
|
||||
if (ctx == null) {
|
||||
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_SYSTEM_VARIABLE, setVar.getVariable());
|
||||
}
|
||||
// for non experimental variables, can not set it with "experimental_" prefix
|
||||
if (hasExpPrefix && ctx.getField().getAnnotation(VarAttr.class).expType() == ExperimentalType.NONE) {
|
||||
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_SYSTEM_VARIABLE, setVar.getVariable());
|
||||
}
|
||||
// Check variable attribute and setVar
|
||||
checkUpdate(setVar, ctx.getFlag());
|
||||
|
||||
@ -518,13 +536,34 @@ public class VariableMgr {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* return the VarContext map with display var name.
|
||||
* For example, if a session variable "foo" is an experimental variable,
|
||||
* its display name is "experimental_foo"
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static ImmutableMap<String, VarContext> getDisplaySessionVars() {
|
||||
Map<String, VarContext> result = Maps.newHashMap();
|
||||
for (Map.Entry<String, VarContext> entry : ctxByVarName.entrySet()) {
|
||||
VarContext varContext = entry.getValue();
|
||||
VarAttr varAttr = varContext.getField().getAnnotation(VarAttr.class);
|
||||
if (varAttr.expType() == ExperimentalType.EXPERIMENTAL) {
|
||||
result.put(ExperimentalUtil.EXPERIMENTAL_PREFIX + entry.getKey(), varContext);
|
||||
} else {
|
||||
result.put(entry.getKey(), varContext);
|
||||
}
|
||||
}
|
||||
return ImmutableMap.copyOf(result);
|
||||
}
|
||||
|
||||
// Dump all fields. Used for `show variables`
|
||||
public static List<List<String>> dump(SetType type, SessionVariable sessionVar, PatternMatcher matcher) {
|
||||
List<List<String>> rows = Lists.newArrayList();
|
||||
// Hold the read lock when session dump, because this option need to access global variable.
|
||||
rlock.lock();
|
||||
try {
|
||||
for (Map.Entry<String, VarContext> entry : ctxByVarName.entrySet()) {
|
||||
for (Map.Entry<String, VarContext> entry : ctxByDisplayVarName.entrySet()) {
|
||||
// Filter variable not match to the regex.
|
||||
if (matcher != null && !matcher.match(entry.getKey())) {
|
||||
continue;
|
||||
@ -589,6 +628,8 @@ public class VariableMgr {
|
||||
|
||||
// Set to true if this variable is fuzzy
|
||||
boolean fuzzy() default false;
|
||||
|
||||
ExperimentalType expType() default ExperimentalType.NONE;
|
||||
}
|
||||
|
||||
private static class VarContext {
|
||||
|
||||
Reference in New Issue
Block a user