hive源码(二)输出日志、hook处理 Driver类

一:org.apache.hadoop.hive.ql.Driver 类流程

部分方法实体较长、可以直接搜素《《很重要》》 关键字,直接看重要代码

CommandProcessorResponse方法
    //重载方法,继续掉用
    return run(command, false);
CommandProcessorResponse重载方法
    try {
       //很重要  下一级代码入口
      runInternal(command, alreadyCompiled);
      return createProcessorResponse(0);
    } catch (CommandProcessorResponse cpr) {

    SessionState ss = SessionState.get();
    if(ss == null) {
      return cpr;
    }
    //不重要 格式化输出 json 文本格式
    MetaDataFormatter mdf = MetaDataFormatUtils.getFormatter(ss.getConf());
    if(!(mdf instanceof JsonMetaDataFormatter)) {
      return cpr;
    }
    ..........//不重要 异常处理代码
    return cpr;
    }
runInternal方法
      ........这一块不想看
      if (!alreadyCompiled) {  //1949 行
        //很重要   sql转成mapreduce过程
        compileInternal(command, true);
        perfLogger = SessionState.getPerfLogger();
      } else {
        perfLogger = SessionState.getPerfLogger();
        plan.setQueryStartTime(perfLogger.getStartTime(PerfLogger.DRIVER_RUN));
      }
      .....
      try {
        //很重要   提交执行mapreduce过程
        execute();//2011行
      } catch (CommandProcessorResponse cpr) {
        rollback(cpr);
        throw cpr;
      }
compileInternal方法
    //不重要 这一块代码  看起来没有任何的含义 +1 -1 lock  
    //不重要 其实这一块的代码是多个客户端请求的时候,并行解析SQL达到最大值 用的锁
    Metrics metrics = MetricsFactory.getInstance();
    if (metrics != null) {
      metrics.incrementCounter(MetricsConstant.WAITING_COMPILE_OPS, 1);
    }
    PerfLogger perfLogger = SessionState.getPerfLogger();
    perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.WAIT_COMPILE);
    //不重要 代码里面最后一行 将锁lock
    final ReentrantLock compileLock = tryAcquireCompileLock(isParallelEnabled,
      command);
    perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.WAIT_COMPILE);
    if (metrics != null) {
      metrics.decrementCounter(MetricsConstant.WAITING_COMPILE_OPS, 1);
    }

    if (compileLock == null) {
      throw createProcessorResponse(ErrorMsg.COMPILE_LOCK_TIMED_OUT.getErrorCode());
    }

    try {
      //很重要   sql转成mapreduce过程
      compile(command, true, deferClose);
    } catch (CommandProcessorResponse cpr) {
      try {
        releaseLocksAndCommitOrRollback(false);
      } catch (LockException e) {
        LOG.warn("Exception in releasing locks. " + org.apache.hadoop.util.StringUtils.stringifyException(e));
      }
      throw cpr;
    } finally {
      compileLock.unlock();
    }
    //不重要 日志相关的选项  忽略
    queryDisplay.setPerfLogStarts(QueryDisplay.Phase.COMPILATION, perfLogger.getStartTimes());
    queryDisplay.setPerfLogEnds(QueryDisplay.Phase.COMPILATION, perfLogger.getEndTimes());
compile方法
    //不重要 日志相关的选项  忽略
    PerfLogger perfLogger = SessionState.getPerfLogger(true);
    perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.DRIVER_RUN);
    perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.COMPILE);
    lDrvState.stateLock.lock();
    try {
      lDrvState.driverState = DriverState.COMPILING;
    } finally {
      lDrvState.stateLock.unlock();
    }
    //不重要 替换sql中的变量
    command = new VariableSubstitution(new HiveVariableSource() {
      @Override
      public Map<StringString> getHiveVariable() {
        return SessionState.get().getHiveVariables();
      }
    }).substitute(conf, command);

    String queryStr = command;
    try {
      //不重要 Hook操作执行的地方  
      //有的数仓中利用这个钩子函数  把每个执行的sql记录在mysql 做数仓表血缘图的输入数据
      queryStr = HookUtils.redactLogString(conf, command);
    } catch (Exception e) {
      LOG.warn("WARNING! Query command could not be redacted." + e);
    }
    //不重要 如果当前操作被杀掉了  就把环境中一些变量销毁掉
    checkInterrupted("at beginning of compilation."nullnull);
    if (ctx != null && ctx.getExplainAnalyze() != AnalyzeState.RUNNING) {
      closeInProcess(false);
    }
    //不重要 一个sql多个mapreduce的时候  taskid(1.2.3.4.5)不需要重置
    if (resetTaskIds) {
      TaskFactory.resetId();
    }
    //不重要 app_771b2de4-da27-4057-8b58-8ea496b914e8 产生、设置SQL
    LockedDriverState.setLockedDriverState(lDrvState);
    String queryId = queryState.getQueryId();
    if (ctx != null) {
      setTriggerContext(queryId);
    }
    this.queryDisplay.setQueryStr(queryStr);
    this.queryDisplay.setQueryId(queryId);
    LOG.info("Compiling command(queryId=" + queryId + "): " + queryStr);
    conf.setQueryString(queryStr);
    if (SessionState.get() != null) {
      SessionState.get().getConf().setQueryString(queryStr);
      SessionState.get().setupQueryCurrentTimestamp();
    }

    //不重要 hive事务管理(仅支持orc文件格式)
    boolean compileError = false;
    boolean parseError = false;
    try {
      if (initTxnMgr != null) {
        queryTxnMgr = initTxnMgr;
      } else {
        queryTxnMgr = SessionState.get().initTxnMgr(conf);
      }
      if (queryTxnMgr instanceof Configurable) {
        ((Configurable) queryTxnMgr).setConf(conf);
      }
      queryState.setTxnManager(queryTxnMgr);
      ShutdownHookManager.removeShutdownHook(shutdownRunner);
      final HiveTxnManager txnMgr = queryTxnMgr;
      shutdownRunner = new Runnable() {
        @Override
        public void run() {
          try {
            releaseLocksAndCommitOrRollback(false, txnMgr);
          } catch (LockException e) {
            LOG.warn("Exception when releasing locks in ShutdownHook for Driver: " +e.getMessage());
          }
        }
      };
      ShutdownHookManager.addShutdownHook(shutdownRunner, SHUTDOWN_HOOK_PRIORITY);
      checkInterrupted("before parsing and analysing the query"nullnull);
      if (ctx == null) {
        ctx = new Context(conf);
        setTriggerContext(queryId);
      }
      ctx.setHiveTxnManager(queryTxnMgr);
      ctx.setStatsSource(statsSource);
      ctx.setCmd(command);
      ctx.setHDFSCleanup(true);
      //不是很重要 将SQL解析成ASTnode 类似于词法解析 不断case when 解析sql 获取所需要的信息就可以了
//里面函数都是一个关键字:一个init和after
//FromClauseParser.g:from后面的sql的匹配规则 SelectClauseParser.g:select后面的sql的匹配规则
//IdentifiersParser.g:函数的解析  HiveParser.g:语法解析的

      //利用Antlr将SQL转换为KW_**  TOK_**类似的树形结构 下图有样例
      perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.PARSE);
      hookRunner.runBeforeParseHook(command);
      ASTNode tree;
      try {
        tree = ParseUtils.parse(command, ctx);
      } catch (ParseException e) {
        parseError = true;
        throw e;
      } finally {
        hookRunner.runAfterParseHook(command, parseError);
      }
      perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.PARSE);
      hookRunner.runBeforeCompileHook(command);


      SessionState.get().getCurrentFunctionsInUse().clear();
      perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.ANALYZE);

      //不重要 刷新元数据信息
      Hive.get().getMSC().flushCache();
      backupContext = new Context(ctx);
      boolean executeHooks = hookRunner.hasPreAnalyzeHooks();
      //不重要 继续Hook
      HiveSemanticAnalyzerHookContext hookCtx = new HiveSemanticAnalyzerHookContextImpl();
      if (executeHooks) {
        hookCtx.setConf(conf);
        hookCtx.setUserName(userName);
        hookCtx.setIpAddress(SessionState.get().getUserIpAddress());
        hookCtx.setCommand(command);
        hookCtx.setHiveOperation(queryState.getHiveOperation());

        tree =  hookRunner.runPreAnalyzeHooks(hookCtx, tree);
      }

//很重要 决定面下面使用什么类继续运行 下一节继续写
      BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(queryState, tree);
      if (!retrial) {
        openTransaction();
        generateValidTxnList();
      }
      //很重要 将语法树转换为物理执行计划
      sem.analyze(tree, ctx);

      if (executeHooks) {
        hookCtx.update(sem);
        hookRunner.runPostAnalyzeHooks(hookCtx, sem.getAllRootTasks());
      }
      LOG.info("Semantic Analysis Completed (retrial = {})", retrial);

      // Retrieve information about cache usage for the query.
      if (conf.getBoolVar(HiveConf.ConfVars.HIVE_QUERY_RESULTS_CACHE_ENABLED)) {
        cacheUsage = sem.getCacheUsage();
      }

      sem.validate();
      perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.ANALYZE);

      checkInterrupted("after analyzing query."nullnull);

      //不重要 这一块见名知意 返回数据的列名、查询记录
      schema = getSchema(sem, conf);
      plan = new QueryPlan(queryStr, sem, perfLogger.getStartTime(PerfLogger.DRIVER_RUN), queryId,
        queryState.getHiveOperation(), schema);

      conf.set("mapreduce.workflow.id""hive_" + queryId);
      conf.set("mapreduce.workflow.name", queryStr);

      if (plan.getFetchTask() != null) {
        plan.getFetchTask().initialize(queryState, plan, null, ctx.getOpContext());
      }

      ...... 后面不重要了
    }

二:org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer 类

sem.analyze(tree, ctx);
    上面返回的是CalcitePlanner
但是CalcitePlanner并没有覆盖em.analyze(tree, ctx); 方法的
所以最终执行的还是BaseSemanticAnalyzer 的analyze 方法
analyze方法
    initCtx(ctx);
    init(true);
    analyzeInternal(ast);//BaseSemanticAnalyzer方法是接口,所以执行CalcitePlanner类的 analyzeInternal 方法

public void analyzeInternal(ASTNode ast) throws SemanticException {//其实调用的是父类的方法
        if (runCBO) {
          super.analyzeInternal(ast, new PlannerContextFactory() {
            @Override
            public PlannerContext create() {
              return new PreCboCtx();
            }
        });
        } else {
          super.analyzeInternal(ast);
        }
    }
所以直接调转:SemanticAnalyzer类里面
posted @ 2022-06-30 19:27  Kotlin  阅读(339)  评论(0编辑  收藏  举报
Live2D