2021SC@SDUSC
在上一次博客中,我有说过我是负责第一部分——从HQL语句转化至抽象语法树AST这一步。而由于这一部分是第一部分,所以我要从命令行开始,理清程序的执行路径。
从$ bin/hive
开始
为什么是hive
我们开启HQL命令行的指令就是bin/hive
,我们前往源代码,可以发现我们执行的这个名为hive的脚本文件
据我所知,hiveserver2
也是一个入口,不过我发现这个hiveserver2
的内部是这个样子的:
也就是说它也是执行了hive
这个脚本,所以我们着重关注hive
就可以了
hive
都做了什么
hive
里面有非常多的条件判断、变量设置等等等等。其中相当一部分都是对环境的检查,源代码里就有注释。这帮助我省去了非常多的工作。而且我的思路是:优先观察这个脚本执行了什么文件。于是我将范围锁定在了以下代码:
26 . "$bin"/hive-config.sh
…………
…………
100 if [ -f "${HIVE_CONF_DIR}/hive-env.sh" ]; then
101 . "${HIVE_CONF_DIR}/hive-env.sh"
…………
…………
314 for i in "$bin"/ext/*.sh ; do
315 . $i
316 done
317
318 for i in "$bin"/ext/util/*.sh ; do
319 . $i
320 done
我首先将前两个排除了,这两个都明显是偏配置向的。
最后一个是在执行/ext
文件夹内的所有的脚本文件:
不过好在这些文件名称是有意义的,cli.sh
指明这是命令行的脚本,cli是“command line interface”的缩写,于是我追到这个文件中:
这个脚本文件指向了这样一个类:
org.apache.hadoop.hive.cli.CliDriver
我们终于接近源代码了
走进CliDriver
看来执行的开端就是CliDriver
这个类了
main
方法
我在CliDriver
中进行概览,看看有没有main
方法
很好!这个类里存在一个main
方法,我相信这是我们的入口。沿着这个代码,我们可以继续前往run
方法
run
方法及它进行的调用
这是第一个问题:oproc是干什么的?我去追索了OptionsProcessor
这个类(虽然这个类的功能从类的名字上能有所猜测,但是还是去看了一下)
OptionsProcessor
中的process_stage1(String)
这个方法
其中,commandLine
所属类CommandLine
和GnuParser
这两个类都已经不是hive内的了,它们属于org.apache.commons.cli
这个包。这说明它们极有可能属于apache的基础框架的一部分。虽然我不打算展开深究了,但是我还是沿着GnuParser
到其父类Parser
看了一眼:
基本可以推断,这一系列的操作是用于解析命令行输入的命令的,而org.apache.commons.cli
这个包很可能是一个用于解析命令行的框架(事实似乎确实如此)
而从process_stage1(String)
这个方法内部的其他操作来看,这个方法处理了输入的字符串,并且将字符串解析的结果存入了类中的一个Map里,我推断这个存储的操作有可能在后续用到,比如有方法会调用这个解析好的命令之类的。总之oproc一定不是只用于验证的。
这个方法本身也利用commandLine
来进行一些操作,可能是一些系统配置吧
我们继续看。
中间跳过一个log4j的初始化(反正就是个很重要的初始化)
我们要注意这两块:
CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class));
if (!oproc.process_stage2(ss)) {
return 2;
}
ss
是牵扯到流的,它的流附上了各种标准流。而且它被作为process_stage2(CliSessionState)
的参数,我们可以向内看一看:
这里呀我们要注意了,执行这个方法的是前面的oproc
这个对象,在之前调用process_stage1(String)
时,commandLine
这个变量已经被初始化了,它是解析我们打开HQL客户端时的命令行命令的结果。而在process_stage2(CliSessionState)
中,利用commandLine
来ss
来进行一些配置。而这一次我可以明确看出这些操作的用处了:-e
、-f
这些都是在命令行执行hive
这个脚本的可用参数啊!这一步应该是在对这些用户输入的参数进行解析与执行。
这里有一个插曲:我看到ss.getConf()
的时候就去找了找,发现这个方法返回的是一个sessionConf
的属性,这个属性来自于CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class))
这里,CliSessionState
的构造方法是这样的:
public CliSessionState(HiveConf conf) {
super(conf);
}
这个类又是继承自SessionState
这个类的……好我们继续挖,这个类的构造方法长这个样子
public SessionState(HiveConf conf) {
this(conf, null);
}
然后它调用的另一个构造方法是
public SessionState(HiveConf conf, String userName) {
this.sessionConf = conf;
………………
………………
好,也就是说getConf()
的来源是new HiveConf(SessionState.class)
,这里就又是一大堆东西了。
但后来我意识到getConf()
这个方法的返回值并没有被接收,我不太能理解,这后面的内容也就不再深究了。
后面有好几个给出了注释的操作,这些操作包括:利用ss.getConf()
的结果进行配置,SessionState
的启动(这是一个有关会话、公共数据、线程等内容的类)等等
在这个方法的最后是这样的一段
它调用了另一个叫executeDriver
的方法。这个方法将之前的操作的核心:ss
,conf
(来自ss.getConf()
),oproc
全部传下了。
总结
我们通过脚本文件找到了CliDriver
,并且发现它第一个执行的是run
方法。我们发现run
方法进行了大量和配置相关的操作,显然这仍然是一系列前置操作。而executeDriver
则是我们接下来需要继续探查的路线了