Spark-源码学习-SparkSQL 系列-代码生成-CodegenContext
一、概述
CodegenContext 作为代码生成的上下文,记录了将要生成的代码中的各种元素,包括变量、函数等。
二、实现
CodegenContext 作为代码生成的上下文,记录了将要生成的代码中的各种元素,包括变量、函数等。
2.1. 属性
2.1.1. references
references 是一个数组,用来保存生成代码中的对象(objects),可以通过 addReferenceObj 方法添加。
2.2. 方法
2.2.1. 变量数组 mutableStates 相关方法
$addMutableState()$
方法用来添加变量,需要指定 Java 类型、变量名称和变量初始化代码。
$addBufferedState()$
用来添加缓冲变量,与常规的状态变量的不同之处是,缓冲变量一般用来存储来自 InternalRow 中的数据,比如一行数据中的某些列等。因此,这些变量仅在类中声明,但是不会在初始化函数中执行,该方法返回的是 ExprCode 对象。
$declareMutableStates()$
用来在生成的 Java 类中声明这些变量(默认均为 private 类型)
$initMutableStates()$
用来在类的初始化函数中生成变量的初始化代码,输出的元素都是每行一个。
2.2.2. 函数相关
除变量外,生成的代码中另一个比较重要的部分是添加的函数。在 CodegenContext 中,$addedFunctions()$ 类型为 Map[String, String],提供了函数名和函数代码的映射关系。在代码生成
的过程中,可以通过 $addNewFunction()$ 方法添加函数,并通过 $declareAddedFunctions()$ 方法声明函数。
2.2.3. 数据类型映射相关方法
从直接执行 Spark 到生成 Java 代码来执行,必然会涉及数据类型方面的对应关系。CodegenContext 中提供了一系列的方法来完成数据类型的映射。
$javaType(dt: DataType)$
根据 Spark 中的 DataType 得到 Java 中的数据类型。可以看到,有些类型属于多对一的关系,例如 IntegerType 和 DateType 都会生成
int
类型。
2.2.4. 辅助方法
此外,CodegenContext 还提供了大量的辅助方法与变量。
$currentVars$
类型为 Seq[ExprCode] 的 currentVars,用来记录生成的各列作为当前算子的输入
$freshName$
freshName 方法与类型为 HashMap [String, Int] 的 freshNameIds 配合,用来生成具有唯一ID 的变量名
$nullSafeExec$
添加 null 检测的逻辑。
ExprValue
ExprValue 是有类型的 Java 表达式片段,即一个 Java 变量或者常量或者计算式。
其有四个子类:
- VariableValue 表示一个局部变量表达式。
- GlobalValue 表示一个全局变量表达式。
- LiteralValue 表示一个字面量表达式(有两个子类: TrueLiteral 和 FalseLiteral)
- SimpleExprValue 表示一个有类型 java 表达式片段,例如:
1+1
。
ExprValue本质内容还是JavaCode中的字符串,只是增加了Java类型。
1 | trait ExprValue extends JavaCode { |
ExprCode
ExprCode 表示一段 Java 代码,使用 InternalRow 作为输入,计算一个 Expression。
1 | case class ExprCode(var code: Block, var isNull: ExprValue, var value: ExprValue) |
code 表示计算表达式的 Java 代码块(如果 isNull 和 value 已经存在,code 中含有空字符串)。isNull 表示表达式计算结果是否是 Null,value 表示表达式计算代码块返回的结果(如果 isNull 为 true,那么 value 是无效的)。
ExprCode 本质内容是 JavaCode 中的字符串,只是它增加了 isNull 和 Value ,用于表示是否为空和返回值信息。