Hive代码分析报告(十一):HQL提交到编译解析过程梳理①

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语句,而这个方法中使用了两个主要的方法进行语句执行:processLineprocessFile 方法。

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进行解析的过程。这也是前面我主要分析的内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值