You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, all modules share a same context named sessionctx.Context, and it brings some problems such as cycle dependency and unnecessary coupling. It's better to have individualized context for distinct modules. With this change, we can improve the maintainability of the codebase with the advantages below:
Each context is only responsible for its own module, and we do not need to have a context with logics from all modules. So it is easier to understand the code.
We can reduce the coupling between modules and avoid cycle dependencies.
We can easily add new fields to the context of a module without affecting other modules.
For example, we can define a new interface EvalContext to provide information for expression evaluations:
Different with the previous design, the above example just uses sessionctx.Context to provide some plain "state" instead of providing "semantics." EvalContext which is a wrapper of sessionctx.Context is the one that provides "semantics" for expression evaluations. In this way, different modules can depend on the packages they really need, and we can avoid cycle dependencies. The design of distinct contexts also brings flexibility because each module can have their own assumptions about the context without putting them together into a single context.
Some New Contexts to Introduce
Some important new contexts are listed below:
EvalContext
As we mentioned above, EvalContext provides information for expression evaluations:
For most expression evaluations, BaseEvalInfo is enough. However, for some other special functions, extra information is required. For example, tidb_is_ddl_owner needs to know whether the current TiDB node is a DDL owner that is not included in BaseEvalInfo, so in this case the input EvalContext should be cast to another interface:
Some extra information can be added to ExtenedEvalContext.
Providing multiple interfaces for eval context is that not cases need all information in an evaluation process. For example, if we want to evaluate an expression from a generated column, BaseEvalInfo is enough. Make an easy way to build EvalContext is helpful for some scenes that we cannot get a sessionctx.Context directly, such as the scene of lighting import.
Since we have multiple interfaces for EvalContext, the method Level returns which level of information the current context can provide. It's return value is EvalContextLevel and is defined as below:
EvalContextLevelBase means the context only provides BaseEvalInfo. It is simple and efficient to build and copy. It is always used in some simple cases, such as evaluating an expression from a generated column.
EvalContextLevelBase means the context provides some more extended info. This type of context is not easy to build, it always reads the information from a inner sessionctx.Context. But we can copy it from to a new one to detach it from the inner sessionctx.Context.
EvalContextLevelFull provides the full context, all expressions can use it as the input. However, it cannot be detached from the inner sessionctx.Context because it should provide some complex states that is hard to copy.
Freeze is a special method that returns a new EvalContext with the specified level. A "frozen" context is not only thread safe, it's inner state should be copied from the previous context and can keep immutable even if the inner sessionctx.Context is changed. This is useful for some cases, such as cursor fetch mode. A context with a higher level can be frozen to a lower level, but a context with a lower level cannot be frozen to a higher level. For example, a context with level EvalContextLevelFull can be frozen to EvalContextLevelExtened or EvalContextLevelBase, but a context with level EvalContextLevelBase cannot be frozen to EvalContextLevelExtened. Freeze a context with any level to EvalContextLevelFull is also not allowed, because this level is not able to be detached from the inner sessionctx.Context.
We should also add a new method EvalContextRequirement to expression.Expression to indicate which level of EvalContext is required for the expression evaluation:
EvalContextRequirement is useful in some scenes such as cursor fetches. If a statement includes an expression which requires a eval context with level EvalContextLevelBase or EvalContextLevelExtened, that means we can fetch the data lazily in cursor fetch mode by cloning the context ignoring whether another new statement is created. Otherwise, we should fall back to
the previous implement to fetch all data before returning the cursor.
ExprBuildContext
ExprBuildContext is a context for building expressions:
typeExprBuildContextinterface {
EvalContext// some other methods...
}
In practice, the procedure of building an expression always needs to do some evaluations, so it also extends the interface EvalContext.
Some methods will replace ExprBuildContext with sessionctx.Context as the input argument:
type functionClass interface {
// getFunction gets a function signature by the types and the counts of given arguments.
- getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error)+ getFunction(ctx ExprBuildContext, args []Expression) (builtinFunc, error)
// verifyArgsByCount verifies the count of parameters.
verifyArgsByCount(l int) error
}
// NewFunction creates a new scalar function or constant via a constant folding.
- func NewFunction(ctx sessionctx.Context, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) {+ func NewFunction(ctx ExprBuildContext, funcName string, retType *types.FieldType, args ...Expression) (Expression, error) {
return newFunctionImpl(ctx, 1, funcName, retType, defaultScalarFunctionCheck, args...)
}
PlanContext
PlanContext is a context for building and optimizing plans:
typePlanContextinterface {
EvalContext// some other methods...
}
PlanContext also extends EvalContext because it needs to do some evaluations in building and optimizing procedure.
Some methods will replace PlanContext with sessionctx.Context as the input argument or return value:
type Plan interface {
...
- SCtx() sessionctx.Context+ Ctx() PlanContext
...
}
These two contexts are used to provide information for methods in interface tables.Table.
table.MutateContext is defined as:
type MutateContext interface {
expression.BuildContext
// ... some other methods
}
It is used to provide context when we are mutating a table and should extend expression.BuildContext to build expressions defined in table.
AllocatorContext is defined as:
type AllocatorContext interface {
// GetTemporaryTable returns some runtime information for temporary tables.
GetTemporaryTable(tbl *model.TableInfo) tableutil.TempTable
}
It only contains one method GetTemporaryTable to provide some runtime information for the temporary table to allocate id in session level instead of global level.
ExecutorContext
ExecutorContext is a context for executor executing:
typeExecutorContextinterface {
EvalContext// some other methods...
}
ExecutorContext also extends EvalContext because it needs to do some evaluations in the executing procedure. The type of ctx inner BaseExecutor will be replaced as ExecutorContext:
type BaseExecutor struct {
- ctx sessionctx.Context+ ctx ExecutorContext
}
Now, we have introduced a lot of contexts. I tried to illustrate the relationship between them in a graphics:
The green color means (at least on implementation of) it is simple and easy to copy/clone. The red color means it's not safe/easy to copy/clone, usually means it still depends on session context.
Currently, all modules share a same context named
sessionctx.Context
, and it brings some problems such as cycle dependency and unnecessary coupling. It's better to have individualized context for distinct modules. With this change, we can improve the maintainability of the codebase with the advantages below:For example, we can define a new interface
EvalContext
to provide information for expression evaluations:And then we can define a new context
evalContext
to implement itDifferent with the previous design, the above example just uses
sessionctx.Context
to provide some plain "state" instead of providing "semantics."EvalContext
which is a wrapper ofsessionctx.Context
is the one that provides "semantics" for expression evaluations. In this way, different modules can depend on the packages they really need, and we can avoid cycle dependencies. The design of distinct contexts also brings flexibility because each module can have their own assumptions about the context without putting them together into a single context.Some New Contexts to Introduce
Some important new contexts are listed below:
EvalContext
As we mentioned above,
EvalContext
provides information for expression evaluations:Only
BaseEvalInfo
is required for now to get the basic information for evaluating expressions. BaseEvalInfo is defined as a immutable struct:For most expression evaluations,
BaseEvalInfo
is enough. However, for some other special functions, extra information is required. For example,tidb_is_ddl_owner
needs to know whether the current TiDB node is a DDL owner that is not included inBaseEvalInfo
, so in this case the inputEvalContext
should be cast to another interface:Some extra information can be added to
ExtenedEvalContext
.Providing multiple interfaces for eval context is that not cases need all information in an evaluation process. For example, if we want to evaluate an expression from a generated column,
BaseEvalInfo
is enough. Make an easy way to buildEvalContext
is helpful for some scenes that we cannot get asessionctx.Context
directly, such as the scene of lighting import.Since we have multiple interfaces for
EvalContext
, the methodLevel
returns which level of information the current context can provide. It's return value isEvalContextLevel
and is defined as below:EvalContextLevelBase
means the context only providesBaseEvalInfo
. It is simple and efficient to build and copy. It is always used in some simple cases, such as evaluating an expression from a generated column.EvalContextLevelBase
means the context provides some more extended info. This type of context is not easy to build, it always reads the information from a innersessionctx.Context
. But we can copy it from to a new one to detach it from the innersessionctx.Context
.EvalContextLevelFull
provides the full context, all expressions can use it as the input. However, it cannot be detached from the innersessionctx.Context
because it should provide some complex states that is hard to copy.Freeze
is a special method that returns a newEvalContext
with the specified level. A "frozen" context is not only thread safe, it's inner state should be copied from the previous context and can keep immutable even if the innersessionctx.Context
is changed. This is useful for some cases, such as cursor fetch mode. A context with a higher level can be frozen to a lower level, but a context with a lower level cannot be frozen to a higher level. For example, a context with levelEvalContextLevelFull
can be frozen toEvalContextLevelExtened
orEvalContextLevelBase
, but a context with levelEvalContextLevelBase
cannot be frozen toEvalContextLevelExtened
. Freeze a context with any level toEvalContextLevelFull
is also not allowed, because this level is not able to be detached from the innersessionctx.Context
.We should also add a new method
EvalContextRequirement
toexpression.Expression
to indicate which level ofEvalContext
is required for the expression evaluation:EvalContextRequirement
is useful in some scenes such as cursor fetches. If a statement includes an expression which requires a eval context with levelEvalContextLevelBase
orEvalContextLevelExtened
, that means we can fetch the data lazily in cursor fetch mode by cloning the context ignoring whether another new statement is created. Otherwise, we should fall back tothe previous implement to fetch all data before returning the cursor.
ExprBuildContext
ExprBuildContext
is a context for building expressions:In practice, the procedure of building an expression always needs to do some evaluations, so it also extends the interface
EvalContext
.Some methods will replace
ExprBuildContext
withsessionctx.Context
as the input argument:PlanContext
PlanContext
is a context for building and optimizing plans:PlanContext
also extendsEvalContext
because it needs to do some evaluations in building and optimizing procedure.Some methods will replace
PlanContext
withsessionctx.Context
as the input argument or return value:table.MutateContext & table.AllocatorContext
These two contexts are used to provide information for methods in interface
tables.Table
.table.MutateContext
is defined as:It is used to provide context when we are mutating a table and should extend
expression.BuildContext
to build expressions defined in table.AllocatorContext
is defined as:It only contains one method
GetTemporaryTable
to provide some runtime information for the temporary table to allocate id in session level instead of global level.ExecutorContext
ExecutorContext
is a context for executor executing:ExecutorContext
also extendsEvalContext
because it needs to do some evaluations in the executing procedure. The type ofctx
innerBaseExecutor
will be replaced asExecutorContext
:Tasks
Expression
EvalContext
to provide context in expression evaluation #49415expression.BuildContext
to build expressions #50661table.Index
#50691table.MutateContext
andtable.AllocatorContext
context #50861PlanContext
to provide context for planner #51070sessionctx.Context
depend on contexts in planner and expression #51149AggFuncUpdateContext
andAggFuncBuildContext
to evaluate and build aggeration functions #51223PlanContext
in separate package outside session #51236table.MutateContext
to separate package outside session #51259expression.EvalContext
in separate packages outsidesessionctx
#51298PlanContext
andEvalContext
/BuildContext
#51381expression.EvalContext
#51419expression.EvalContext
#51477EvalContext
should not provide propertyEnableVectorizedExpression
#51563RequireOptionalEvalProps
explicitly #51656expression.PushDownContext
to provide information for context push down #51890The text was updated successfully, but these errors were encountered: