private void processTableScans(MapWork work, Set<TableScanOperator> tableScans) {
    Map<Path, Boolean> managedEmptyPathMap = new HashMap<>();
    Map<Path, Collection<String>> candidatePathsToAliases = new HashMap<>();
    Map<String, Boolean> aliasTypeMap = new HashMap<>();
    Map<String, Map<Path, Partition>> allowedAliasesToPartitions = new HashMap<>();
    int numberOfUnmanagedPaths = 0;
    for (TableScanOperator tso : tableScans) {
      // use LinkedHashMap<String, Operator<? extends OperatorDesc>>
      // getAliasToWork() should not apply this for non-native table
      if (tso.getConf().getTableMetadata().getStorageHandler() != null) {
        continue;
      }
      String alias = getAliasForTableScanOperator(work, tso);
      boolean isManagedTable = !MetaStoreUtils.isExternalTable(tso.getConf().getTableMetadata().getTTable());
      aliasTypeMap.put(alias, isManagedTable);
      allowedAliasesToPartitions.put(alias, getPathToPartitionMap(alias, tso));
      tso.getConf().setIsMetadataOnly(true);
    }

    for (Path path : work.getPaths()) {
      List<String> aliases = work.getPathToAliases().get(path);
      for (String alias: aliases) {
        Map<Path, Partition> pathToPartitionMap = allowedAliasesToPartitions.get(alias);
        if (pathToPartitionMap == null) {
          continue;
        }
        candidatePathsToAliases.computeIfAbsent(path, k -> new ArrayList<>()).add(alias);
        Partition partitionObject = pathToPartitionMap.get(path);
        Map<String, String> partitionParameters = partitionObject != null ? partitionObject.getParameters() : null;
        boolean isManagedTable = aliasTypeMap.get(alias);
        if (isManagedTable && partitionParameters != null && StatsSetupConst.areBasicStatsUptoDate(partitionParameters)) {
          long rwCount = Long.parseLong(partitionParameters.get(StatsSetupConst.ROW_COUNT));
          if (rwCount == 0) {
            managedEmptyPathMap.put(path, true);
          } else {
            managedEmptyPathMap.put(path, false);
          }
        } else {
          numberOfUnmanagedPaths++;
        }
      }
    }

    int fetcherPoolParallelism = Math.min(maxAsyncLookupCount, numberOfUnmanagedPaths);
    ExecutorService executorService = null;
    if (fetcherPoolParallelism > 1) { // don't create executor service for one partition
      executorService = Executors.newFixedThreadPool(fetcherPoolParallelism,
          new ThreadFactoryBuilder().setDaemon(true).setNameFormat("NullScanOptimizer_lookup#%d").build());
    }
    List<Future<?>> lookupFutures = new ArrayList<>(numberOfUnmanagedPaths);
    for (Entry<Path, Collection<String>> entry : candidatePathsToAliases.entrySet()) {
      Path path = entry.getKey();
      Collection<String> allowed = entry.getValue();
      Boolean isEmpty = managedEmptyPathMap.get(path);
      // if isEmpty is null, either stats are not up to date or this is external table
      if (isEmpty == null) {
        if (executorService != null) {
          Future<?> f = executorService.submit(() -> lookupAndProcessPath(work, path, allowed));
          lookupFutures.add(f);
        } else {
          lookupAndProcessPath(work, path, allowed);
        }
      } else {
        processPath(work, path, allowed, isEmpty);
      }
    }
    try {
      for (Future<?> future : lookupFutures) {
          future.get();
      }
    } catch (ExecutionException | InterruptedException e) {
      for (Future<?> f : lookupFutures) {
        f.cancel(true);
      }
      LOG.error("NullScanOptimizer could not complete. It may miss eliminating some null scans", e);
    }
    if (executorService != null) {
      executorService.shutdown();
    }
  }
Iterate over all tasks one by one and removes all input paths from task if
conditions as defined in rules match.
ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/NullScanTaskDispatcher.java