/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.master.file.meta;

import alluxio.AlluxioURI;
import alluxio.exception.ExceptionMessage;
import alluxio.master.journal.JournalContext;
import alluxio.proto.journal.File;
import alluxio.proto.journal.Journal;
import alluxio.retry.ExponentialBackoffRetry;
import alluxio.retry.RetryPolicy;
import alluxio.security.authorization.Mode;
import alluxio.underfs.UnderFileSystem;
import alluxio.underfs.options.MkdirsOptions;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * Utility methods for inodes.
 */
public final class InodeUtils {
  private static final Logger LOG = LoggerFactory.getLogger(InodeUtils.class);

  private InodeUtils() {} // prevent instantiation

  /**
   * Synchronously persists an {@link InodeDirectory} to the UFS. If concurrent calls are made, only
   * one thread will persist to UFS, and the others will wait until it is persisted.
   *
   * @param dir the {@link InodeDirectory} to persist
   * @param inodeTree the {@link InodeTree}
   * @param mountTable the {@link MountTable}
   * @param journalContext the journal context
   * @throws IOException if the file fails to persist
   */
  public static void syncPersistDirectory(InodeDirectory dir, InodeTree inodeTree,
      MountTable mountTable, JournalContext journalContext) throws IOException {
    RetryPolicy retry = new ExponentialBackoffRetry(2, 1000, 50);
    while (dir.getPersistenceState() != PersistenceState.PERSISTED) {
      if (dir.compareAndSwap(PersistenceState.NOT_PERSISTED,
          PersistenceState.TO_BE_PERSISTED)) {
        boolean success = false;
        String errorDetails = "Inode: " + dir.toString();
        try {
          AlluxioURI uri = inodeTree.getPath(dir);
          MountTable.Resolution resolution = mountTable.resolve(uri);
          String ufsUri = resolution.getUri().toString();
          errorDetails += " ufsUri: " + ufsUri;
          UnderFileSystem ufs = resolution.getUfs();
          MkdirsOptions mkdirsOptions =
              MkdirsOptions.defaults().setCreateParent(false).setOwner(dir.getOwner())
                  .setGroup(dir.getGroup()).setMode(new Mode(dir.getMode()));
          if (!ufs.isDirectory(ufsUri)) {
            ufs.mkdirs(ufsUri, mkdirsOptions);
          }
          dir.setPersistenceState(PersistenceState.PERSISTED);

          // Append the persist entry to the journal.
          File.PersistDirectoryEntry persistDirectory =
              File.PersistDirectoryEntry.newBuilder().setId(dir.getId()).build();
          journalContext.append(
              Journal.JournalEntry.newBuilder().setPersistDirectory(persistDirectory).build());
          success = true;
        } catch (Exception e) {
          // Ignore
          LOG.warn("Failed to persist directory to UFS: {} : {}", errorDetails, e.getMessage());
          LOG.debug("Exception: ", e);
        } finally {
          if (!success) {
            // Failed to persist the inode, so set the state back to NOT_PERSISTED.
            dir.setPersistenceState(PersistenceState.NOT_PERSISTED);
          }
        }
      } else {
        if (!retry.attemptRetry()) {
          throw new IOException(ExceptionMessage.FAILED_UFS_CREATE.getMessage(dir.getName()));
        }
      }
    }
  }
}

@@ -1178,16 +1178,433 @@
 .class);
+%0A  /** The base amount (exponential backoff) to sleep before retrying persisting an inode. */%0A  private static final int PERSIST_WAIT_BASE_SLEEP_MS = 2;%0A  /** Maximum amount (exponential backoff) to sleep before retrying persisting an inode. */%0A  private static final int PERSIST_WAIT_MAX_SLEEP_MS = 1000;%0A  /** The maximum retries for persisting an inode. */%0A  private static final int PERSIST_WAIT_MAX_RETRIES = 50;
 %0A%0A  priv
@@ -2284,16 +2284,24 @@
  retry =
+%0A       
  new Exp
@@ -2325,19 +2325,99 @@
 try(
-2, 1000, 50
+PERSIST_WAIT_BASE_SLEEP_MS, PERSIST_WAIT_MAX_SLEEP_MS,%0A            PERSIST_WAIT_MAX_RETRIES
 );%0A 
@@ -2640,16 +2640,23 @@
   String
+Builder
  errorDe
@@ -2667,20 +2667,44 @@
 s = 
-%22Inode: %22 + 
+new StringBuilder(%22Inode: %22).append(
 dir.
@@ -2705,32 +2705,33 @@
 d(dir.toString()
+)
 ;%0A        try %7B%0A
@@ -2935,12 +2935,16 @@
 ails
- += 
+.append(
 %22 uf
@@ -2954,17 +2954,24 @@
 i: %22
- + 
+).append(
 ufsUri
+)
 ;%0A  
@@ -3868,17 +3868,42 @@
 rDetails
-,
+.toString(),%0A             
  e.getMe

Use constants and StringBuilder