hive执行流程
整个流程的第一步,就是cli提交作业给driver,这一步需要通过org.apache.hadoop.hive.cli.CliDriver
类。
CliDriver类
首先看CliDriver
类的main
方法。
org.apache.hadoop.hive.cli.CliDriver
----------
/**
* 输入参数String[] args不需要分析,是外部命令传进来的参数
*/
public static void main(String[] args) throws Exception {
// run 运行函数
int ret = (new CliDriver()).run(args);
// exit 退出函数
System.exit(ret);
}
exit
是退出函数,对源码注解直译内容为:
终止当前正在运行的java虚拟机。这个参数作为状态码;按惯例,非零状态代码表示异常终止。与return不同,return只是退回到上一层,exit将会退出到最外层。
java.lang.System
----------
/**
* Terminates the currently running Java Virtual Machine. The
* argument serves as a status code; by convention, a nonzero status
* code indicates abnormal termination.
* <p>
* This method calls the <code>exit</code> method in class
* <code>Runtime</code>. This method never returns normally.
* <p>
* The call <code>System.exit(n)</code> is effectively equivalent to
* the call:
* <blockquote><pre>
* Runtime.getRuntime().exit(n)
* </pre></blockquote>
*
* @param status exit status.
* @throws SecurityException
* if a security manager exists and its <code>checkExit</code>
* method doesn't allow exit with the specified status.
* @see java.lang.Runtime#exit(int)
*/
public static void exit(int status) {
Runtime.getRuntime().exit(status);
}
run
函数表示作业开始正式提交,最主要的是他建立新的CliDriver
对象,并调用run
函数。
所以我们先看CliDriver
的创建过程,再看run
函数。
org.apache.hadoop.hive.cli.CliDriver
----------
/**
* CliDriver构造函数
*/
public CliDriver() {
// 创建一个SessionState,SessionState内部保存大量配置信息
// SessionState在hive中大量使用,是很重要的
SessionState ss = SessionState.get();
// 三目表达式,就是将ss内部的配置信息给conf
this.conf = (Configuration)(ss != null ? ss.getConf() : new Configuration());
// 获取CliDriver的log
Logger LOG = LoggerFactory.getLogger("CliDriver");
// 是否启动debug,如果启动的话会实时打印一些信息
if (LOG.isDebugEnabled()) {
LOG.debug("CliDriver inited with classpath {}", System.getProperty("java.class.path"));
}
// 一个管理日志的类
this.console = new LogHelper(LOG);
}
在看run
方法前先来看看SessionState
的get
函数。SessionState
封装了一个会话的关联的数据,包括配置信息HiveConf
,输入输出流,指令类型,用户名称、IP地址等等。
SessionState
是一个与线程关联的静态本地变量ThreadLocal
,任何一个线程都对应一个SessionState
。
org.apache.hadoop.hive.ql.session.SessionState
----------
/**
* 获取当前会话,返回了一个对象tss的调用
* SessionState中有一个很重要的知识点ThreadLocal,本节不做分析
*/
public static SessionState get() {
return ((SessionState.SessionStates)tss.get()).state;
}
上面创建了一个富含各种信息的CliDriver
对象,现在来看他怎么调用run
方法。
public int run(String[] args) throws Exception {
// 1.建立OptionsProcessor类的对象oproc,并且对命令进行初步的解析.
// 提取-e -h hiveconf hivevar等参数信息,设置用户提供的系统和Hive环境变量。
OptionsProcessor oproc = new OptionsProcessor();
if (!oproc.process_stage1(args)) {
return 1;
} else {
// 2.初始化Log4j日志组件
boolean logInitFailed = false;
String logInitDetailMessage;
try {
logInitDetailMessage = LogUtils.initHiveLog4j();
} catch (LogInitializationException var15) {
logInitFailed = true;
logInitDetailMessage = var15.getMessage();
}
// 3.使用HiveConf实例化CliSessionState,CliSessionState继承了SessionState类
// 创建了输入输出流,也创建了一些记录用户输入的字符串,
// 比如:fileName,cmdProperties,在实例化的过程中,主要是用来记录HiveConf。
CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class));
ss.in = System.in;
try {
ss.out = new PrintStream(System.out, true, "UTF-8");
ss.info = new PrintStream(System.err, true, "UTF-8");
ss.err = new CachingPrintStream(System.err, true, "UTF-8");
} catch (UnsupportedEncodingException var14) {
return 3;
}
// 4.根据stage1解析的参数内容,填充CliSessionState的字符串
// 比如用户输入了-e 则这个stage就把-e 对应的字符串赋值给CliSessionState的 execString成员。
// -S 表示 沉默状态
// -e 获取执行sql
// -f 获取要执行的sql文件
// -v 是否详细显示
// 其他, 处理hiveconf 和 i 等参数
if (!oproc.process_stage2(ss)) {
return 2;
} else {
// 5.在允许打印的模式下,如果初始化日志失败就打印错误信息
if (!ss.getIsSilent()) {
if (logInitFailed) {
System.err.println(logInitDetailMessage);
} else {
SessionState.getConsole().printInfo(logInitDetailMessage);
}
}
// 6.将用户命令行输入的配置信息和变量等覆盖HiveConf的默认值
HiveConf conf = ss.getConf();
Iterator var7 = ss.cmdProperties.entrySet().iterator();
while(var7.hasNext()) {
Entry<Object, Object> item = (Entry)var7.next();
conf.set((String)item.getKey(), (String)item.getValue());
ss.getOverriddenConfigurations().put((String)item.getKey(), (String)item.getValue());
}
// 7.读取配置提示和替换变量
prompt = conf.getVar(ConfVars.CLIPROMPT);
prompt = (new VariableSubstitution(new HiveVariableSource() {
public Map<String, String> getHiveVariable() {
return SessionState.get().getHiveVariables();
}
})).substitute(conf, prompt);
prompt2 = spacesForString(prompt);
// 8.设置会话状态,然后执行CLI程序,即excuteDriver().
if (HiveConf.getBoolVar(conf, ConfVars.HIVE_CLI_TEZ_SESSION_ASYNC)) {
SessionState.beginStart(ss, this.console);
} else {
SessionState.start(ss);
}
ss.updateThreadName();
int var16;
try {
var16 = this.executeDriver(ss, conf, oproc);
} finally {
ss.resetThreadName();
ss.close();
}
return var16;
}
}
}
大致的流程可以整理为:
- 读取命令行输入的参数,保存在
OptionsProcessor
对象oproc
中 - 初始化Log4j日志组件
- 创建
CliSessionState
对象ss
读取SessionState
内配置信息 - 接着对
CliSessionState
对象进行初始化,如果报错且允许打印则输出报错信息 - 将
CliSessionState
对象ss
读取SessionState
内配置信息覆盖默认配置信息 - 完成替换后做好允许准备,进入下一步骤。
简单来说就是读取相关环境配置,开启日志,读取相关配置覆盖默认配置,准备允许。