public StoreFileWriter build() throws IOException {
      if ((dir == null ? 0 : 1) + (liveFilePath == null ? 0 : 1) != 1) {
        throw new IllegalArgumentException("Either specify parent directory " + "or file path");
      }

      if (dir == null) {
        dir = liveFilePath.getParent();
      }

      if (!fs.exists(dir)) {
        // Handle permission for non-HDFS filesystem properly
        // See HBASE-17710
        HRegionFileSystem.mkdirs(fs, conf, dir);
      }

      // set block storage policy for temp path
      String policyName = this.conf.get(ColumnFamilyDescriptorBuilder.STORAGE_POLICY);
      if (null == policyName) {
        policyName = this.conf.get(HStore.BLOCK_STORAGE_POLICY_KEY);
      }
      CommonFSUtils.setStoragePolicy(this.fs, dir, policyName);

      if (liveFilePath == null) {
        // The stored file and related blocks will used the directory based StoragePolicy.
        // Because HDFS DistributedFileSystem does not support create files with storage policy
        // before version 3.3.0 (See HDFS-13209). Use child dir here is to make stored files
        // satisfy the specific storage policy when writing. So as to avoid later data movement.
        // We don't want to change whole temp dir to 'fileStoragePolicy'.
        if (!Strings.isNullOrEmpty(fileStoragePolicy)) {
          dir = new Path(dir, HConstants.STORAGE_POLICY_PREFIX + fileStoragePolicy);
          if (!fs.exists(dir)) {
            HRegionFileSystem.mkdirs(fs, conf, dir);
            LOG.info(
              "Create tmp dir " + dir.toString() + " with storage policy: " + fileStoragePolicy);
          }
          CommonFSUtils.setStoragePolicy(this.fs, dir, fileStoragePolicy);
        }
        liveFilePath = getUniqueFile(fs, dir);
        if (!BloomFilterFactory.isGeneralBloomEnabled(conf)) {
          bloomType = BloomType.NONE;
        }
      }

      if (isCompaction && shouldEnableHistoricalCompactionFiles(conf)) {
        historicalFilePath = getUniqueFile(fs, dir);
      }

      // make sure we call this before actually create the writer
      // in fact, it is not a big deal to even add an inexistent file to the track, as we will never
      // try to delete it and finally we will clean the tracker up after compaction. But if the file
      // cleaner find the file but we haven't recorded it yet, it may accidentally delete the file
      // and cause problem.
      if (writerCreationTracker != null) {
        writerCreationTracker.accept(liveFilePath);
        if (historicalFilePath != null) {
          writerCreationTracker.accept(historicalFilePath);
        }
      }
      return new StoreFileWriter(fs, liveFilePath, historicalFilePath, conf, cacheConf, bloomType,
        maxKeyCount, favoredNodes, fileContext, shouldDropCacheBehind, compactedFilesSupplier,
        comparator, maxVersions, newVersionBehavior);
    }
Create a store file writer. Client is responsible for closing file when done. If metadata,
add BEFORE closing using {@link StoreFileWriter#appendMetadata}.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFileWriter.java