2021SC@SDUSC
目录
概述
HIVE的组成层次
从用户接口提交到进入编译解析
概述
前面的文章中,我们小组通过对代码的阅读和分析以及查阅资料,简单分析了HIVE中HQL语句从输入命令行(用户接口)到进入编译(语义分析)的简单流程。这里我汇总一下前面的分析内容,对HIVE的前两个主要流程进行梳理。
HIVE的组成层次
Hive 主要分为三个层次:
1. Interfaces:这是Hive 对外提供的使用接口
主要包括命令行接口、web 接口、基于thrift 协议的服务接口、基于JDBC/ODBC 协议的数据库接口。
2. Query Engine(Driver):这是Hive 的核心,也就是所说的引擎
3. Hadoop:这一部分其实并不包含在Hive 之中,它是HIVE 存储/计算的实际的载体
这三个层次之间的主要交互是:Interfaces 将字符串形式的HQL 语句传递给QueryEngine 中的编译器;编译器将plan.xml 传递给运行时;运行时反序列化plan.xml,执行其中指定的任务,并将Job 提交给Hadoop。当然,除了MapReduce 任务之外,任务也可能是本地任务、元数据任务、hdfs 任务。
从用户接口提交到进入编译解析
hive源码的入口是CliDriver类,这个类中的main方法调用了run方法执行HQL语句。
run中的主要代码:
1: 创建OptionsProcessor对象解析hive执行前的可选参数
2: 创建CliSessionState对象ss,创建过程中会把hive配置文件中的一些配置参数加载进来
3: 获取 HiveConf 对象 conf,并进行一些配置项的加载
4: 执行 executeDriver 方法执行HQL语句,而这个方法中使用了两个主要的方法进行语句执行:processLine
和 processFile
方法。
processFile()
processFile 中最主要的代码如下:rc = processReader(bufferReader);
public int processReader(BufferedReader r) throws IOException {
String line;
StringBuilder qsb = new StringBuilder();
while ((line = r.readLine()) != null) {
// Skipping through comments
if (! line.startsWith("--")) {
qsb.append(line + "\n");
}
}
return (processLine(qsb.toString()));
}
我们可以看到其实 processReader 只是把文件读进来,去掉注释语句,然后对其调用processLine 方法。
而processLine 会把我们写的所有SQL语句用分号; 拆开然后对每一句执行 processCmd
方法,有一句不成功就会返回失败。
public int processLine(String line, boolean allowInterrupting) {
...............
// we can not use "split" function directly as ";" may be quoted
int lastRet = 0, ret = 0;
List<String> commands = splitSemiColon(line);
String command = "";
for (String oneCmd : commands) {
if (StringUtils.endsWith(oneCmd, "\\")) {
command += StringUtils.chop(oneCmd) + ";";
continue;
} else {
command += oneCmd;
}
if (StringUtils.isBlank(command)) {
continue;
}
ret = processCmd(command);
command = "";
lastRet = ret;
}
proc的获取是通过processCmd获取的,其中tokens是一句SQL语句用空白符分隔开的字符串数组(即组成SQL的一个一个词组成的数组)CommandProcessor proc = CommandProcessorFactory.get(tokens, (HiveConf) conf);
接着,getForHiveCommand(cmd, conf)这个方法中就简单调用了 getForHiveCommandInternal
方法
可以看到该方法能根据不同SQL得到不同的CommandProcessor对象proc。
接着就是执行DRIVER的run方法了,而这个的run方法中可以看出最终执行的是 runInternal
这个方法
从Driver中的run方法可以看出Hive中SQL的执行主要分两步,第一步先对SQL进行解析,第二步执行解析后的SQL。
run()方法的具体流程:
1. 初始化errorMsg 和SQLState 为null;
2. 调用compile(cmd)完成对HQL cmd 的编译,生成执行计划plan;
3. 调用acquireReadWriteLocks()获取plan 中输入输出需要的读写锁;
4. 调用execute()执行plan;
5. 释放Context ctx 中记录的已经获取的锁;
6. 返回带有0 错误码的CommandProcessorResponse;
注意,在2、3、4 中,如果有任何一步失败(返回值不为0),都会释放ctx 中已经获取的锁,并将返回带有非0 错误码的CommandProcessorResponse。
以上就是HQL语句从用户接口提交后进入编译阶段的简单过程梳理,下一篇我将继续梳理查询引擎对HQL进行解析的过程。这也是前面我主要分析的内容。