@Override public AsynchronousFileChannel newAsynchronousFileChannel( Path path, Set<? extends OpenOption> options, @Nullable ExecutorService executor, FileAttribute<?>... attrs) throws IOException { // call newFileChannel and cast so that FileChannel support is checked there JimfsFileChannel channel = (JimfsFileChannel) newFileChannel(path, options, attrs); if (executor == null) { JimfsFileSystem fileSystem = (JimfsFileSystem) path.getFileSystem(); executor = fileSystem.getDefaultThreadPool(); } return channel.asAsynchronousFileChannel(executor); }
@Override public long position() throws IOException { checkOpen(); long pos; synchronized (this) { boolean completed = false; try { begin(); // don't call beginBlocking() because this method doesn't block if (!isOpen()) { return 0; // AsynchronousCloseException will be thrown } pos = this.position; completed = true; } finally { end(completed); } } return pos; }
@Override public FileChannel truncate(long size) throws IOException { Util.checkNotNegative(size, "size"); checkOpen(); checkWritable(); synchronized (this) { boolean completed = false; try { if (!beginBlocking()) { return this; // AsynchronousCloseException will be thrown } file.writeLock().lockInterruptibly(); try { file.truncate(size); if (position > size) { position = size; } file.updateModifiedTime(); completed = true; } finally { file.writeLock().unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { endBlocking(completed); } } return this; }
/** * Begins a blocking operation, making the operation interruptible. Returns {@code true} if the * channel was open and the thread was added as a blocking thread; returns {@code false} if the * channel was closed. */ private boolean beginBlocking() { begin(); synchronized (blockingThreads) { if (isOpen()) { blockingThreads.add(Thread.currentThread()); return true; } return false; } }
@Override public int read(ByteBuffer dst) throws IOException { checkNotNull(dst); checkOpen(); checkReadable(); boolean completed = false; try { if (!beginBlocking()) { return 0; // AsynchronousCloseException will be thrown Thread.currentThread().interrupt(); } finally { endBlocking(completed);
private void checkLockArguments(long position, long size, boolean shared) throws IOException { Util.checkNotNegative(position, "position"); Util.checkNotNegative(size, "size"); checkOpen(); if (shared) { checkReadable(); } else { checkWritable(); } }
@Override public FileLock lock(long position, long size, boolean shared) throws IOException { checkLockArguments(position, size, shared); // lock is interruptible boolean completed = false; try { begin(); completed = true; return new FakeFileLock(this, position, size, shared); } finally { try { end(completed); } catch (ClosedByInterruptException e) { throw new FileLockInterruptionException(); } } }
@Override public long size() throws IOException { checkOpen(); long size = 0; // will definitely either be assigned or an exception will be thrown boolean completed = false; try { if (!beginBlocking()) { return 0; // AsynchronousCloseException will be thrown } file.readLock().lockInterruptibly(); try { size = file.sizeWithoutLocking(); completed = true; } finally { file.readLock().unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { endBlocking(completed); } return size; }
@Override public ListenableFuture<FileLock> lock( final long position, final long size, final boolean shared) { Util.checkNotNegative(position, "position"); Util.checkNotNegative(size, "size"); if (!isOpen()) { return closedChannelFuture(); } if (shared) { channel.checkReadable(); } else { channel.checkWritable(); } return executor.submit( new Callable<FileLock>() { @Override public FileLock call() throws IOException { return tryLock(position, size, shared); } }); }
private JimfsFileChannel newJimfsFileChannel( JimfsPath path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException { ImmutableSet<OpenOption> opts = Options.getOptionsForChannel(options); FileSystemView view = getDefaultView(path); RegularFile file = view.getOrCreateRegularFile(path, opts, attrs); return new JimfsFileChannel(file, opts, view.state()); }
/** * Ends a blocking operation, throwing an exception if the thread was interrupted while blocking * or if the channel was closed from another thread. */ private void endBlocking(boolean completed) throws AsynchronousCloseException { synchronized (blockingThreads) { blockingThreads.remove(Thread.currentThread()); } end(completed); }
@Override public FileLock tryLock(long position, long size, boolean shared) throws IOException { checkLockArguments(position, size, shared); // tryLock is not interruptible return new FakeFileLock(this, position, size, shared); }
@Override public void close() throws IOException { channel.close(); }
@Override public ListenableFuture<Integer> write(final ByteBuffer src, final long position) { Util.checkNotNegative(position, "position"); if (!isOpen()) { return closedChannelFuture(); } channel.checkWritable(); return executor.submit( new Callable<Integer>() { @Override public Integer call() throws IOException { return channel.write(src, position); } }); }
@Override public ListenableFuture<Integer> read(final ByteBuffer dst, final long position) { checkArgument(!dst.isReadOnly(), "dst may not be read-only"); Util.checkNotNegative(position, "position"); if (!isOpen()) { return closedChannelFuture(); } channel.checkReadable(); return executor.submit( new Callable<Integer>() { @Override public Integer call() throws IOException { return channel.read(dst, position); } }); }
@Override public int read(ByteBuffer dst, long position) throws IOException { checkNotNull(dst); Util.checkNotNegative(position, "position"); checkOpen(); checkReadable(); int read = 0; // will definitely either be assigned or an exception will be thrown // no need to synchronize here; this method does not make use of the channel's position boolean completed = false; try { if (!beginBlocking()) { return 0; // AsynchronousCloseException will be thrown } file.readLock().lockInterruptibly(); try { read = file.read(position, dst); file.updateAccessTime(); completed = true; } finally { file.readLock().unlock(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { endBlocking(completed); } return read; }
@Override public FileLock tryLock(long position, long size, boolean shared) throws IOException { Util.checkNotNegative(position, "position"); Util.checkNotNegative(size, "size"); channel.checkOpen(); if (shared) { channel.checkReadable(); } else { channel.checkWritable(); } return new JimfsFileChannel.FakeFileLock(this, position, size, shared); }
@Override public FileLock lock(long position, long size, boolean shared) throws IOException { checkLockArguments(position, size, shared); // lock is interruptible boolean completed = false; try { begin(); completed = true; return new FakeFileLock(this, position, size, shared); } finally { try { end(completed); } catch (ClosedByInterruptException e) { throw new FileLockInterruptionException(); } } }