Class FileHandle

java.lang.Object
io.deephaven.engine.util.file.FileHandle
All Implemented Interfaces:
Closeable, AutoCloseable, ByteChannel, Channel, ReadableByteChannel, SeekableByteChannel, WritableByteChannel

public final class FileHandle extends Object implements SeekableByteChannel

A representation of an open file. Designed to ensure predictable cleanup for open file descriptors.

This class is basically just a wrapper around a FileChannel that only exposes some of its methods. It serves two purposes:

  1. It creates an extra layer of indirection between the FileChannel and application code, to allow for reachability-sensitive cleanup.
  2. It's a convenient place to add instrumentation and/or modified implementations when necessary.

The current implementation adds a post-close procedure for integration with caches/trackers, and stats for all operations.

Note that positional methods, e.g. position(), position(long), read(ByteBuffer), and write(ByteBuffer) may require external synchronization if used concurrently by more than one thread.

  • Constructor Summary

    Constructors
    Constructor
    Description
    FileHandle(@NotNull FileChannel fileChannel, @NotNull Runnable postCloseProcedure)
  • Method Summary

    Modifier and Type
    Method
    Description
    final void
    Close this file handle and release underlying resources.
    boolean
    equalsFileKey(@NotNull FileHandle other)
    Checks if two file handles are equal based on their BasicFileAttributes.fileKey() on a best-effort basis.
    final void
    Force updates (including metadata) to the underlying file to be written to *local* storage.
    final boolean
    Tells whether this file handle is open.
    static FileHandle
    open(@NotNull Path path, @NotNull Supplier<Runnable> postCloseProcedureSupplier, @NotNull OpenOption... options)
    Creates a new file handle by wrapping up the results of an FileChannel.open(Path, OpenOption...).
    final long
    Get this file handle's position.
    position(long newPosition)
    Advance the position of this file handle to the specified new position.
    final int
    read(@NotNull ByteBuffer destination)
    Attempt to read destination.remaining() bytes, beginning at the handle's current position and updating that position by the number of bytes read.
    final int
    read(@NotNull ByteBuffer destination, long position)
    Attempt to read destination.remaining() bytes, starting from position (0-indexed) in the file.
    final long
    Get the current size of the file.
    truncate(long size)
    Truncate this file to the supplied size.
    final int
    write(@NotNull ByteBuffer source)
    Attempt to write source.remaining() bytes to this file handle, beginning at the handle's current position (which is first advanced to the end of the file, if the underlying FileChannel was opened with StandardOpenOption.APPEND), and updating that position by the number of bytes written.
    final int
    write(@NotNull ByteBuffer source, long position)
    Attempt to write source.remaining() bytes, starting from position (0-indexed) in the file.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

  • Method Details

    • open

      public static FileHandle open(@NotNull @NotNull Path path, @NotNull @NotNull Supplier<Runnable> postCloseProcedureSupplier, @NotNull @NotNull OpenOption... options) throws IOException
      Creates a new file handle by wrapping up the results of an FileChannel.open(Path, OpenOption...).

      If the Runnable created from postCloseProcedureSupplier throws an exception, that exception may suppress ClosedChannelExceptions that trigger postCloseProcedure invocation.

      By default, the returned file handle will contain its file key to act as a safety check during refreshes of the file handle as part of FileHandleAccessor. To disable this safety check, the configuration property "FileHandle.safetyCheckEnabled" can be set to false.

      Parameters:
      path - The path to the file
      postCloseProcedureSupplier - A supplier for a procedure to invoke if it's detected that the FileChannel is closed - the procedure must be idempotent. The supplier will be called exactly once after the FileChannel has been successfully created.
      options - the open options
      Returns:
      the file handle
      Throws:
      IOException - if an IO exception occurs
    • equalsFileKey

      public boolean equalsFileKey(@NotNull @NotNull FileHandle other)
      Checks if two file handles are equal based on their BasicFileAttributes.fileKey() on a best-effort basis. This method should only return false when it is known that the file handles refer to different files - that is, the bias is for this method to return true. The exact semantics of "file key equivalence" is filesystem-dependant, but the general expectation is that UNIX filesystems will use device ID and inode to accomplish this. (A UNIX filesystem may choose to re-use device ID and inode after a file has been deleted. In this case, it is possible for two file handles that referenced two separate files to have "file key equivalence", and is one of the reason why this method must be biased in the true direction.)

      If the configuration property "FileHandle.safetyCheckEnabled" is false, this method will always return true.

      Parameters:
      other - the other file handle
      Returns:
      true if the file keys are equal
    • size

      public final long size() throws IOException

      Get the current size of the file.

      See FileChannel.size().

      Specified by:
      size in interface SeekableByteChannel
      Returns:
      The current size of the file
      Throws:
      IOException
    • position

      public final long position() throws IOException

      Get this file handle's position.

      See FileChannel.position().

      Specified by:
      position in interface SeekableByteChannel
      Returns:
      This file handle's position
      Throws:
      IOException
    • position

      public final FileHandle position(long newPosition) throws IOException

      Advance the position of this file handle to the specified new position.

      See FileChannel.position(long).

      Specified by:
      position in interface SeekableByteChannel
      Parameters:
      newPosition - The new position
      Returns:
      This file handle
      Throws:
      IOException
    • read

      public final int read(@NotNull @NotNull ByteBuffer destination, long position) throws IOException

      Attempt to read destination.remaining() bytes, starting from position (0-indexed) in the file.

      See FileChannel.read(ByteBuffer, long).

      Parameters:
      destination - The destination to read to
      position - The position in the file to start reading from
      Returns:
      The number of bytes read, or -1 if end of file is reached
      Throws:
      IOException
    • read

      public final int read(@NotNull @NotNull ByteBuffer destination) throws IOException

      Attempt to read destination.remaining() bytes, beginning at the handle's current position and updating that position by the number of bytes read.

      See FileChannel.read(ByteBuffer).

      Specified by:
      read in interface ReadableByteChannel
      Specified by:
      read in interface SeekableByteChannel
      Parameters:
      destination - The destination to read to
      Returns:
      The number of bytes read, or -1 of end of file is reached
      Throws:
      IOException
    • write

      public final int write(@NotNull @NotNull ByteBuffer source, long position) throws IOException

      Attempt to write source.remaining() bytes, starting from position (0-indexed) in the file.

      See FileChannel.write(ByteBuffer, long).

      Parameters:
      source - The source to write from
      position - The position in the file to start writing at
      Returns:
      The number of bytes written
      Throws:
      IOException
    • write

      public final int write(@NotNull @NotNull ByteBuffer source) throws IOException

      Attempt to write source.remaining() bytes to this file handle, beginning at the handle's current position (which is first advanced to the end of the file, if the underlying FileChannel was opened with StandardOpenOption.APPEND), and updating that position by the number of bytes written.

      See FileChannel.write(ByteBuffer).

      Specified by:
      write in interface SeekableByteChannel
      Specified by:
      write in interface WritableByteChannel
      Parameters:
      source - The source to write from
      Returns:
      The number of bytes written
      Throws:
      IOException
    • truncate

      public final FileHandle truncate(long size) throws IOException

      Truncate this file to the supplied size.

      See FileChannel.truncate(long).

      Specified by:
      truncate in interface SeekableByteChannel
      Parameters:
      size - The new size
      Returns:
      This handle
      Throws:
      IOException
    • force

      public final void force() throws IOException

      Force updates (including metadata) to the underlying file to be written to *local* storage.

      See FileChannel.force(boolean).

      Throws:
      IOException
    • isOpen

      public final boolean isOpen()

      Tells whether this file handle is open.

      See AbstractInterruptibleChannel.isOpen().

      Specified by:
      isOpen in interface Channel
      Returns:
      If the file handle is open
    • close

      public final void close() throws IOException

      Close this file handle and release underlying resources.

      See AbstractInterruptibleChannel.close().

      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Channel
      Specified by:
      close in interface Closeable
      Throws:
      IOException