Class Underlock

java.lang.Object
com.atlassian.secrets.service.dao.Underlock

public class Underlock extends Object
Utility class used to edit a file, complete with locking to prevent concurrent edits by other cluster nodes or git processes.
  • Method Details

    • forFile

      public static Underlock forFile(Path file)
    • forFile

      public static Underlock forFile(Path file, Duration timeout)
    • edit

      public void edit(IoBiConsumer<? super BufferedReader,? super Writer> mutator, boolean withBackup) throws IOException, OverlappingFileLockException
      Edits the file, complete with locking to prevent concurrent edits by other cluster nodes or git processes.

      If the file already exists, the mutator receives an Reader for it. Otherwise, the first argument will be null. The mutator always receives an Writer, for emitting the new contents.

      The primary use case for this method is guarding an edit with a lock.

      Parameters:
      mutator - a function to use for mutating the file
      withBackup - whether the old version of the file should be saved with a .bak extension
      Throws:
      IOException - if the mutator fails, or if the file cannot be locked
      OverlappingFileLockException - if the file can't be locked because it has already been locked
    • editRaw

      public void editRaw(IoBiConsumer<? super InputStream,? super OutputStream> mutator, boolean withBackup) throws IOException
      Edits the file, complete with locking to prevent concurrent edits by other cluster nodes or git processes.

      If the file already exists, the mutator receives an InputStream for it. Otherwise, the first argument will be null. The mutator always receives an OutputStream, for emitting the new contents.

      The primary use case for this method is guarding an edit with a lock.

      Parameters:
      mutator - a function to use for mutating the file
      withBackup - whether the old version of the file should be saved with a .bak extension
      Throws:
      IOException - if the mutator fails, or if the file cannot be locked
      OverlappingFileLockException - if the file can't be locked because it has already been locked
    • lock

      Acquires a lock on the file, returning a Underlock.LockedFile that can be used to release the lock.
      Returns:
      a Underlock.LockedFile that when closed, releases the lock
      Throws:
      IOException - if an I/O error occurred when acquiring the lock
      OverlappingFileLockException - if the lock could not be acquired within the specified timeout
    • lockIndefinitely

      public void lockIndefinitely(@Nullable String content) throws IOException, OverlappingFileLockException
      Checks whether the lock is currently held, and if not, creates the lock file with the provided content as the file content.

      The effect of this operation is that any attempt to acquire an exclusive lock or edit the target file under lock will fail, which is useful for situations where the lock should survive node restarts, (e.g. pausing of garbage collection).

      Throws:
      IOException - if an I/O error occurred when acquiring the lock
      OverlappingFileLockException - if the lock could not be acquired within the specified timeout
    • releaseIfNotHeld

      public void releaseIfNotHeld() throws IOException
      Releases a previously acquired lock, including stale lock files, or locks that were created through lockIndefinitely(String). If the lock file does not exist, nothing happens.
      Throws:
      IOException - if the lock cannot be released
      OverlappingFileLockException - if another process or thread is actively holding the lock
    • releaseIfNotHeld

      public void releaseIfNotHeld(@Nullable Runnable cleanupTask) throws IOException
      Releases a previously acquired lock, including stale lock files, or locks that were created through lockIndefinitely(String). If the lock is successfully released, the provided cleanup task is run. If the lock file does not exist the cleanup task is not run and nothing happens.
      Throws:
      IOException - if the lock cannot be released
      OverlappingFileLockException - if another process or thread is actively holding the lock
    • write

      public void write(ReadableByteChannel source) throws IOException
      Acquires a lock on the file, and then writes the contents of the provided ReadableByteChannel to it. Contents are written to the lock first and then renamed into place to produce an (effectively) atomic write even on NFS.
      Parameters:
      source - the contents to write
      Throws:
      IOException - if the file cannot be locked, or the contents cannot be written
      OverlappingFileLockException - if the file can't be locked because it has already been locked