private int aggregateStats(Hive db, Table tbl) {

    StatsAggregator statsAggregator = null;
    int ret = 0;
    StatsCollectionContext scc = null;
    EnvironmentContext environmentContext = null;
    environmentContext = new EnvironmentContext();
    environmentContext.putToProperties(StatsSetupConst.DO_NOT_UPDATE_STATS, StatsSetupConst.TRUE);

    try {
      // Stats setup:
      final Warehouse wh = new Warehouse(conf);
      if (!getWork().getNoStatsAggregator() && !getWork().isNoScanAnalyzeCommand()) {
        try {
          scc = getContext();
          statsAggregator = createStatsAggregator(scc, conf);
        } catch (HiveException e) {
          if (HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_STATS_RELIABLE)) {
            throw e;
          }
          console.printError(ErrorMsg.STATS_SKIPPING_BY_ERROR.getErrorCodedMsg(e.toString()));
        }
      }

      List<Partition> partitions = getPartitionsList(db);

      String tableFullName = table.getDbName() + "." + table.getTableName();

      if (partitions == null) {
        Partish p = new Partish.PTable(table);

        BasicStatsProcessor basicStatsProcessor = new BasicStatsProcessor(p, work, followedColStats);
        basicStatsProcessor.collectFileStatus(wh, conf);
        Table res = (Table) basicStatsProcessor.process(statsAggregator);
        if (res == null) {
          return 0;
        }
        db.alterTable(tableFullName, res, environmentContext, true);

        TransactionalStatsProcessor transactionalStatsProcessor = new TransactionalStatsProcessor(db, p);
        transactionalStatsProcessor.process(statsAggregator);

        if (conf.getBoolVar(ConfVars.TEZ_EXEC_SUMMARY)) {
          console.printInfo("Table " + tableFullName + " stats: [" + toString(p.getPartParameters()) + ']');
        } else {
          LOG.info("Table " + tableFullName + " stats: [" + toString(p.getPartParameters()) + ']');
        }

        // The table object is assigned to the latest table object.
        // So that it can be used by ColStatsProcessor.
        // This is only required for unpartitioned tables.
        tbl.setTTable(res.getTTable());

      } else {
        // Partitioned table:
        // Need to get the old stats of the partition
        // and update the table stats based on the old and new stats.

        List<Partition> updates = Lists.newArrayList();

        final ExecutorService pool = buildBasicStatsExecutor();

        final List<Future<Void>> futures = Lists.newLinkedList();
        List<BasicStatsProcessor> processors = Lists.newLinkedList();
        List<TransactionalStatsProcessor> transactionalStatsProcessors = Lists.newLinkedList();

        try {
          for (final Partition partn : partitions) {
            Partish p = new Partish.PPart(table, partn);
            
            BasicStatsProcessor bsp = new BasicStatsProcessor(p, work, followedColStats);
            processors.add(bsp);
            transactionalStatsProcessors.add(new TransactionalStatsProcessor(db, p));

            futures.add(pool.submit(new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                bsp.collectFileStatus(wh, conf);
                return null;
              }
            }));
          }
          pool.shutdown();
          for (Future<Void> future : futures) {
            future.get();
          }
        } catch (InterruptedException e) {
          LOG.debug("Cancelling " + futures.size() + " file stats lookup tasks");
          //cancel other futures
          for (Future future : futures) {
            future.cancel(true);
          }
          // Fail the query if the stats are supposed to be reliable
          if (work.isStatsReliable()) {
            ret = 1;
          }
        } finally {
          pool.shutdownNow();
          LOG.debug("Finished getting file stats of all partitions!");
        }

        for (BasicStatsProcessor basicStatsProcessor : processors) {
          Object res = basicStatsProcessor.process(statsAggregator);
          if (res == null) {
            LOG.info("Partition " + basicStatsProcessor.partish.getPartition().getSpec() + " stats: [0]");
            continue;
          }
          updates.add((Partition) res);
          if (conf.getBoolVar(ConfVars.TEZ_EXEC_SUMMARY)) {
            console.printInfo("Partition " + basicStatsProcessor.partish.getPartition().getSpec() + " stats: [" + toString(basicStatsProcessor.partish.getPartParameters()) + ']');
          } else {
            LOG.info("Partition " + basicStatsProcessor.partish.getPartition().getSpec() + " stats: [" + toString(basicStatsProcessor.partish.getPartParameters()) + ']');
          }
        }

        if (!updates.isEmpty()) {
          db.alterPartitions(tableFullName, updates, environmentContext, true);
        }

        for (TransactionalStatsProcessor transactionalStatsProcessor : transactionalStatsProcessors) {
          transactionalStatsProcessor.process(statsAggregator);
        }

        if (work.isStatsReliable() && updates.size() != processors.size()) {
          LOG.info("Stats should be reliadble...however seems like there were some issue.. => ret 1");
          ret = 1;
        }
      }

    } catch (Exception e) {
      console.printInfo("[Warning] could not update stats.",
          "Failed with exception " + e.getMessage() + "\n"
              + StringUtils.stringifyException(e));

      // Fail the query if the stats are supposed to be reliable
      if (work.isStatsReliable()) {
        ret = 1;
      }
    } finally {
      if (statsAggregator != null) {
        statsAggregator.closeConnection(scc);
      }
    }
    // The return value of 0 indicates success,
    // anything else indicates failure
    return ret;
  }
StatsTask implementation. StatsTask mainly deals with "collectable" stats. These are
stats that require data scanning and are collected during query execution (unless the user
explicitly requests data scanning just for the purpose of stats computation using the "ANALYZE"
command. All other stats are computed directly by the MetaStore. The rationale being that the
MetaStore layer covers all Thrift calls and provides better guarantees about the accuracy of
those stats.
ql/src/java/org/apache/hadoop/hive/ql/stats/BasicStatsTask.java