/**
  * @param fs
  * @param hTableDescriptor
  * @param tableDir
  * @param status
  * @return Descriptor file or null if we failed write.
  * @throws IOException
  */
 private static Path writeTableDescriptor(
     final FileSystem fs,
     final HTableDescriptor hTableDescriptor,
     final Path tableDir,
     final FileStatus status)
     throws IOException {
   // Get temporary dir into which we'll first write a file to avoid
   // half-written file phenomeon.
   Path tmpTableDir = new Path(tableDir, ".tmp");
   // What is current sequenceid?  We read the current sequenceid from
   // the current file.  After we read it, another thread could come in and
   // compete with us writing out next version of file.  The below retries
   // should help in this case some but its hard to do guarantees in face of
   // concurrent schema edits.
   int currentSequenceid = status == null ? 0 : getTableInfoSequenceid(status.getPath());
   int sequenceid = currentSequenceid;
   // Put arbitrary upperbound on how often we retry
   int retries = 10;
   int retrymax = currentSequenceid + retries;
   Path tableInfoPath = null;
   do {
     sequenceid += 1;
     Path p = getTableInfoFileName(tmpTableDir, sequenceid);
     if (fs.exists(p)) {
       LOG.debug(p + " exists; retrying up to " + retries + " times");
       continue;
     }
     try {
       writeHTD(fs, p, hTableDescriptor);
       tableInfoPath = getTableInfoFileName(tableDir, sequenceid);
       if (!fs.rename(p, tableInfoPath)) {
         throw new IOException("Failed rename of " + p + " to " + tableInfoPath);
       }
     } catch (IOException ioe) {
       // Presume clash of names or something; go around again.
       LOG.debug("Failed write and/or rename; retrying", ioe);
       if (!FSUtils.deleteDirectory(fs, p)) {
         LOG.warn("Failed cleanup of " + p);
       }
       tableInfoPath = null;
       continue;
     }
     // Cleanup old schema file.
     if (status != null) {
       if (!FSUtils.deleteDirectory(fs, status.getPath())) {
         LOG.warn("Failed delete of " + status.getPath() + "; continuing");
       }
     }
     break;
   } while (sequenceid < retrymax);
   return tableInfoPath;
 }
 /** Deletes a table's directory from the file system if exists. Used in unit tests. */
 public static void deleteTableDescriptorIfExists(String tableName, Configuration conf)
     throws IOException {
   FileSystem fs = FSUtils.getCurrentFileSystem(conf);
   FileStatus status = getTableInfoPath(fs, FSUtils.getRootDir(conf), tableName);
   // The below deleteDirectory works for either file or directory.
   if (status != null && fs.exists(status.getPath())) {
     FSUtils.deleteDirectory(fs, status.getPath());
   }
 }