public static AcidDirectory getAcidState(FileSystem fileSystem, Path candidateDirectory, Configuration conf,
      ValidWriteIdList writeIdList, Ref<Boolean> useFileIds, boolean ignoreEmptyFiles, Map<Path,
      HdfsDirSnapshot> dirSnapshots) throws IOException {
    ValidTxnList validTxnList = getValidTxnList(conf);

    FileSystem fs = fileSystem == null ? candidateDirectory.getFileSystem(conf) : fileSystem;
    AcidDirectory directory = new AcidDirectory(candidateDirectory, fs, useFileIds);

    List<HdfsFileStatusWithId> childrenWithId = HdfsUtils.tryListLocatedHdfsStatus(useFileIds, fs, candidateDirectory, HIDDEN_FILES_PATH_FILTER);

    if (childrenWithId != null) {
      for (HdfsFileStatusWithId child : childrenWithId) {
        getChildState(directory, child, writeIdList,validTxnList, ignoreEmptyFiles);
      }
    } else {
      if (dirSnapshots == null) {
        dirSnapshots = getHdfsDirSnapshots(fs, candidateDirectory);
      }
      getChildState(directory, dirSnapshots, writeIdList, validTxnList, ignoreEmptyFiles);
    }
    // If we have a base, the original files are obsolete.
    if (directory.getBase() != null) {
      // Add original files to obsolete list if any
      for (HdfsFileStatusWithId fswid : directory.getOriginalFiles()) {
        directory.getObsolete().add(fswid.getFileStatus().getPath());
      }
      // Add original directories to obsolete list if any
      directory.getObsolete().addAll(directory.getOriginalDirectories());
      // remove the entries so we don't get confused later and think we should
      // use them.
      directory.getOriginalFiles().clear();
      directory.getOriginalDirectories().clear();
    } else {
      // Okay, we're going to need these originals.
      // Recurse through them and figure out what we really need.
      // If we already have the original list, do nothing
      // If childrenWithId != null, we would have already populated "original"
      if (childrenWithId != null) {
        for (Path origDir : directory.getOriginalDirectories()) {
          directory.getOriginalFiles().addAll(HdfsUtils.listFileStatusWithId(fs, origDir, useFileIds, true, null));
        }
      }
    }
    // Filter out all delta directories that are shadowed by others
    findBestWorkingDeltas(writeIdList, directory);

    if(directory.getOldestBase() != null && directory.getBase() == null &&
        isCompactedBase(directory.getOldestBase(), fs, dirSnapshots)) {
      /*
       * If here, it means there was a base_x (> 1 perhaps) but none were suitable for given
       * {@link writeIdList}.  Note that 'original' files are logically a base_Long.MIN_VALUE and thus
       * cannot have any data for an open txn.  We could check {@link deltas} has files to cover
       * [1,n] w/o gaps but this would almost never happen...
       *
       * We only throw for base_x produced by Compactor since that base erases all history and
       * cannot be used for a client that has a snapshot in which something inside this base is
       * open.  (Nor can we ignore this base of course)  But base_x which is a result of IOW,
       * contains all history so we treat it just like delta wrt visibility.  Imagine, IOW which
       * aborts. It creates a base_x, which can and should just be ignored.*/
      long[] exceptions = writeIdList.getInvalidWriteIds();
      String minOpenWriteId = exceptions != null && exceptions.length > 0 ?
        Long.toString(exceptions[0]) : "x";
      throw new IOException(ErrorMsg.ACID_NOT_ENOUGH_HISTORY.format(
        Long.toString(writeIdList.getHighWatermark()),
              minOpenWriteId, directory.getOldestBase().toString()));
    }

    Path basePath = directory.getBaseDirectory();
    if (basePath != null) {
      boolean isBaseInRawFormat = MetaDataFile.isRawFormat(basePath, fs, dirSnapshots != null ? dirSnapshots.get(basePath) : null);
      directory.getBase().setRawFormat(isBaseInRawFormat);
    }
    LOG.debug("in directory " + candidateDirectory.toUri().toString() + " base = " + basePath + " deltas = " +
        directory.getCurrentDirectories().size());
    /*
     * If this sort order is changed and there are tables that have been converted to transactional
     * and have had any update/delete/merge operations performed but not yet MAJOR compacted, it
     * may result in data loss since it may change how
     * {@link org.apache.hadoop.hive.ql.io.orc.OrcRawRecordMerger.OriginalReaderPair} assigns
     * {@link RecordIdentifier#rowId} for read (that have happened) and compaction (yet to happen).
     */
    // this does "Path.uri.compareTo(that.uri)"
    directory.getOriginalFiles().sort(Comparator.comparing(HdfsFileStatusWithId::getFileStatus));
    return directory;
  }
GetAcidState implementation which uses the provided dirSnapshot.
Generates a new one if needed and the provided one is null.
@param fileSystem optional, it it is not provided, it will be derived from the candidateDirectory
@param candidateDirectory the partition directory to analyze
@param conf the configuration
@param writeIdList the list of write ids that we are reading
@param useFileIds It will be set to true, if the FileSystem supports listing with fileIds
@param ignoreEmptyFiles Ignore files with 0 length
@param dirSnapshots The listed directory snapshot, if null new will be generated
@return the state of the directory
@throws IOException on filesystem errors
ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java