hive0.13 rows loaded为空问题源码分析及fix

升级hive0.13之后发现job运行完成后Rows loaded的信息没有了。

rows loaded的信息在hive0.11中由HiveHistory类的printRowCount输出。HiveHistory类的主要用途是记录job运行的信息,包括task的counter等。默认的目录在/tmp/$user中。

hive0.11在SessionState 的start方法中会初始化HiveHistory的对象

 if (startSs. hiveHist == null) {
      startSs. hiveHist = new HiveHistory(startSs);
    }

而在hive0.13中HiveHistory是一个抽象类,其具体的实现在HiveHistoryImpl类中,其中初始化HiveHistoryImpl对象时增加了一层判断,判断hive.session.history.enabled的设置(默认为false),导致不会实例化HiveHistoryImpl类

  if(startSs.hiveHist == null){
      if (startSs.getConf().getBoolVar(HiveConf.ConfVars.HIVE_SESSION_HISTORY_ENABLED)) {
        startSs.hiveHist = new HiveHistoryImpl (startSs);
      }else {
        //Hive history is disabled, create a no-op proxy
        startSs.hiveHist = HiveHistoryProxyHandler .getNoOpHiveHistoryProxy();
      }
    }

在fix这个配置之后,仍然没有发现rows loaded的信息,通过分析源码

printRowCount方法的实现如下:

  public void printRowCount(String queryId) {
    QueryInfo ji = queryInfoMap.get(queryId);
    if (ji == null) {   // 如果ji为空,则直接返回
      return;
    }
    for (String tab : ji. rowCountMap.keySet()) {
      console.printInfo(ji. rowCountMap.get(tab) + " Rows loaded to " + tab); // 从hashmap中获取数据
    }
  }

在hive0.13中,这里获取的ji对象是空值。

近一步发现,是由于counter中没有TABLE_ID_(\\d+)_ROWCOUNT,导致不能匹配ROW_COUNT_PATTERN的正则。就不能正常获取的row count的值。

其中获取tasker count的rows loaded信息的getRowCountTableName方法内容如下:

private static final String ROW_COUNT_PATTERN = "TABLE_ID_(\\d+)_ROWCOUNT";
  private static final Pattern rowCountPattern = Pattern.compile(ROW_COUNT_PATTERN);
......
  String getRowCountTableName(String name) {
    if (idToTableMap == null) {
      return null;
    }
    Matcher m = rowCountPattern.matcher(name);
    if (m.find()) {  // //没有和TABLE_ID_xxxx match的counter导致,即counter没有打印出TABLE_ID_(\\d+)_ROWCOUNT导致。。
      String tuple = m.group(1);
      return idToTableMap.get(tuple);
    }
    return null;
  }

而TABLE_ID_(\\d+)_ROWCOUNT是由FileSinkOperator类负责写入的。hive0.11中相关的代码如下:

  protected void initializeOp(Configuration hconf) throws HiveException {
..........
      int id = conf.getDestTableId();
      if ((id != 0) && (id <= TableIdEnum. values().length)) {
        String enumName = "TABLE_ID_" + String.valueOf(id) + "_ROWCOUNT";
        tabIdEnum = TableIdEnum.valueOf(enumName);
        row_count = new LongWritable();
        statsMap.put( tabIdEnum, row_count );
      }

而在hive0.13中这部分代码都被去掉了,找到了原因,fix也比较简单,把这个counter加回去就可了。

patch如下:

diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
index 1dde78e..96860f7 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
@@ -68,13 +68,16 @@
import org.apache.hadoop.util.ReflectionUtils;
import com.google.common.collect.Lists;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
/**
  * File Sink operator implementation.
  **/
public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
     Serializable {
-
+  public static Log LOG = LogFactory.getLog("FileSinkOperator.class");
   protected transient HashMap<String, FSPaths> valToPaths;
   protected transient int numDynParts;
   protected transient List<String> dpColNames;
@@ -214,6 +217,7 @@ public Stat getStat() {
   protected transient FileSystem fs;
   protected transient Serializer serializer;
   protected transient LongWritable row_count;
+  protected transient TableIdEnum tabIdEnum = null;
   private transient boolean isNativeTable = true;
   /**
@@ -241,6 +245,23 @@ public Stat getStat() {
   protected transient JobConf jc;
   Class<? extends Writable> outputClass;
   String taskId;
+  public static enum TableIdEnum {
+       TABLE_ID_1_ROWCOUNT,
+       TABLE_ID_2_ROWCOUNT,
+       TABLE_ID_3_ROWCOUNT,
+       TABLE_ID_4_ROWCOUNT,
+       TABLE_ID_5_ROWCOUNT,
+       TABLE_ID_6_ROWCOUNT,
+       TABLE_ID_7_ROWCOUNT,
+       TABLE_ID_8_ROWCOUNT,
+       TABLE_ID_9_ROWCOUNT,
+       TABLE_ID_10_ROWCOUNT,
+       TABLE_ID_11_ROWCOUNT,
+       TABLE_ID_12_ROWCOUNT,
+       TABLE_ID_13_ROWCOUNT,
+       TABLE_ID_14_ROWCOUNT,
+       TABLE_ID_15_ROWCOUNT;
+  }
   protected boolean filesCreated = false;
@@ -317,7 +338,15 @@ protected void initializeOp(Configuration hconf) throws HiveException {
         prtner = (HivePartitioner<HiveKey, Object>) ReflectionUtils.newInstance(
             jc.getPartitionerClass(), null);
       }
-      row_count = new LongWritable();
+      //row_count = new LongWritable();
+         int id = conf.getDestTableId();
+         if ((id != 0) && (id <= TableIdEnum.values().length)) {
+               String enumName = "TABLE_ID_" + String.valueOf(id) + "_ROWCOUNT";  
+               tabIdEnum = TableIdEnum.valueOf(enumName);
+               row_count = new LongWritable();
+               statsMap.put(tabIdEnum, row_count);
+         }
+
       if (dpCtx != null) {
         dpSetup();
       }

打完patch后,重新打包,替换线上的hive-exec-xxx.jar包之后测试,rows loaded的数据又回来了。

时间: 2024-10-29 14:09:48

hive0.13 rows loaded为空问题源码分析及fix的相关文章

【python】13位随机序列号生成工具 源码分析

By Dolphin,BeiJing,20150712 0X00  背景 最近在学习python 这门语言,刚学完for循环,对于很多语句语法都不太熟悉.就在今天,看到有某个网站的活动,需要输入一个13位的序列号来判断你是否中奖,但是这个13位序列号是需要购买他们家的产品才能获得,得耗费一定的金钱,于是我就在想,是不是能自己写一个序列号生成器来碰碰运气,所以决定运用刚学的python的初级知识进行编写. 0X01  知识点准备 这个工具主要的功能是生成随机字母做序列号,python中的rando

Mesos源码分析

Mesos源码分析(1): Mesos的启动过程总论 Mesos源码分析(2): Mesos Master的启动之一 Mesos源码分析(3): Mesos Master的启动之二 Mesos源码分析(4) Mesos Master的启动之三 Mesos源码分析(5): Mesos Master的启动之四 Mesos源码分析(6): Mesos Master的初始化 Mesos源码分析(7): Mesos-Slave的启动 Mesos源码分析(8): Mesos-Slave的初始化 Mesos源

Solr4.8.0源码分析(13)之LuceneCore的索引修复

Solr4.8.0源码分析(13)之LuceneCore的索引修复 题记:今天在公司研究elasticsearch,突然看到一篇博客说elasticsearch具有索引修复功能,顿感好奇,于是点进去看了下,发现原来是Lucene Core自带的功能,于是就回家先学习下,正好也跟之前看的索引文件的格式相应.有空也研究下Lucene的一些小工具. 索引的修复主要是用到CheckIndex.java这个类,可以直接查看类的Main函数来了解下. 1. CheckIndex的使用 首先使用以下命令来查看

Solr4.8.0源码分析(19)之缓存机制(二)

Solr4.8.0源码分析(19)之缓存机制(二) 前文<Solr4.8.0源码分析(18)之缓存机制(一)>介绍了Solr缓存的生命周期,重点介绍了Solr缓存的warn过程.本节将更深入的来介绍下Solr的四种缓存类型,以及两种SolrCache接口实现类. 1.SolrCache接口实现类 前文已经提到SolrCache有两种接口实现类:solr.search.LRUCache 和 solr.search.LRUCache. 那么两者具体有啥区别呢? 1.1 solr.search.LR

EasyUI学习总结(三)——easyloader源码分析

EasyUI学习总结(三)--easyloader源码分析 easyloader模块是用来加载jquery easyui的js和css文件的,而且它可以分析模块的依赖关系,先加载依赖项.模块加载好了会调用parse模块来解析页面.把class是easyui开头的标签都转化成easyui的控件. 先看Demo1例子,再分析源代码. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>easyloader范例</tit

Impala 源码分析-FE

By yhluo 2015年7月29日 Impala 3 Comments Impala 源代码目录结构 SQL 解析 Impala 的 SQL 解析与执行计划生成部分是由 impala-frontend(Java)实现的,监听端口是 21000.用户通过Beeswax 接口 BeeswaxService.query() 提交一个请求,在 impalad 端的处理逻辑是由void ImpalaServer::query(QueryHandle& query_handle, const Query

【Spring源码分析】配置文件读取流程

前言 Spring配置文件读取流程本来是和http://www.cnblogs.com/xrq730/p/6285358.html一文放在一起的,这两天在看Spring自定义标签的时候,感觉对Spring配置文件读取流程还是研究得不够,因此将Spring配置文件读取流程部分从之前的文章拆出来单独成为一文. 为了看一下Spring配置文件加载流程,先定义一个bean.xml: 1 <?xml version="1.0" encoding="UTF-8"?>

EasyUI学习总结(三)——easyloader源码分析(转载)

声明:这一篇文章是转载过来的,转载地址忘记了,原作者如果看到了,希望能够告知一声,我好加上去! easyloader模块是用来加载jquery easyui的js和css文件的,而且它可以分析模块的依赖关系,先加载依赖项.模块加载好了会调用parse模块来解析页面.把class是easyui开头的标签都转化成easyui的控件. 先看Demo1例子,再分析源代码. 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>ea

ImageLoader源码分析

1.介绍 ImageLoader是Android平台必备的图片加载.缓存.显示库,配置选项丰富.下面列表内容是我从小米note文件夹复制的ImageLoader磁盘缓存文件夹列表,足以说明ImageLoader用户量之大. com.miui.systemAdSolution com.android.email com.xiaomi.mitunes com.baidu.BaiduMap com.miui.mipub com.miui.cleanmaster com.miui.analytics c