All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.paralleluniverse.fibers.io.FiberFileChannel Maven / Gradle / Ivy

Go to download

The core library for Fibers on Java, compatible with Java 11-16. Forked from puniverse/quasar

There is a newer version: 10.0.6
Show newest version
/*
 * Quasar: lightweight threads and actors for the JVM.
 * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
 * 
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *  
 *   or (per the licensee's choosing)
 *  
 * under the terms of the GNU Lesser General Public License version 3.0
 * as published by the Free Software Foundation.
 */
package co.paralleluniverse.fibers.io;

import co.paralleluniverse.common.util.CheckedCallable;
import co.paralleluniverse.fibers.Suspendable;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.spi.FileSystemProvider;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * A fiber-blocking version of {@link FileChannel}.
 *
 * @author pron
 */
public class FiberFileChannel implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel {
    private static final ExecutorService fiberFileThreadPool = Executors.newCachedThreadPool(
            new ThreadFactoryBuilder().setDaemon(true).setNameFormat("fiber-file-open-%d").build());
    private static final FileAttribute[] NO_ATTRIBUTES = new FileAttribute[0];

    private final AsynchronousFileChannel ac;
    private long position;

    FiberFileChannel(AsynchronousFileChannel afc) {
        ac = afc;
    }

    /**
     * Opens or creates a file, returning a file channel to access the file.
     *
     * 

The {@code options} parameter determines how the file is opened. * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE * WRITE} options determine if the file should be opened for reading and/or * writing. If neither option (or the {@link StandardOpenOption#APPEND APPEND} * option) is contained in the array then the file is opened for reading. * By default reading or writing commences at the beginning of the file. * *

In the addition to {@code READ} and {@code WRITE}, the following * options may be present: * *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
additional options
Option Description
{@link StandardOpenOption#APPEND APPEND} If this option is present then the file is opened for writing and * each invocation of the channel's {@code write} method first advances * the position to the end of the file and then writes the requested * data. Whether the advancement of the position and the writing of the * data are done in a single atomic operation is system-dependent and * therefore unspecified. This option may not be used in conjunction * with the {@code READ} or {@code TRUNCATE_EXISTING} options.
{@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} If this option is present then the existing file is truncated to * a size of 0 bytes. This option is ignored when the file is opened only * for reading.
{@link StandardOpenOption#CREATE_NEW CREATE_NEW} If this option is present then a new file is created, failing if * the file already exists. When creating a file the check for the * existence of the file and the creation of the file if it does not exist * is atomic with respect to other file system operations. This option is * ignored when the file is opened only for reading.
{@link StandardOpenOption#CREATE CREATE} If this option is present then an existing file is opened if it * exists, otherwise a new file is created. When creating a file the check * for the existence of the file and the creation of the file if it does * not exist is atomic with respect to other file system operations. This * option is ignored if the {@code CREATE_NEW} option is also present or * the file is opened only for reading.
{@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} When this option is present then the implementation makes a * best effort attempt to delete the file when closed by * the {@link #close close} method. If the {@code close} method is not * invoked then a best effort attempt is made to delete the file * when the Java virtual machine terminates.
{@link StandardOpenOption#SPARSE SPARSE} When creating a new file this option is a hint that the * new file will be sparse. This option is ignored when not creating * a new file.
{@link StandardOpenOption#SYNC SYNC} Requires that every update to the file's content or metadata be * written synchronously to the underlying storage device. (see Synchronized I/O file * integrity).
{@link StandardOpenOption#DSYNC DSYNC} Requires that every update to the file's content be written * synchronously to the underlying storage device. (see Synchronized I/O file * integrity).
* *

An implementation may also support additional options. * *

The {@code attrs} parameter is an optional array of file {@link * FileAttribute file-attributes} to set atomically when creating the file. * *

The new channel is created by invoking the {@link * FileSystemProvider#newFileChannel newFileChannel} method on the * provider that created the {@code Path}. * * @param path The path of the file to open or create * @param options Options specifying how the file is opened * @param ioExecutor The thread pool or {@code null} to associate the channel with the default thread pool * @param attrs An optional list of file attributes to set atomically when creating the file * * @return A new file channel * * @throws IllegalArgumentException If the set contains an invalid combination of options * @throws UnsupportedOperationException If the {@code file} is associated with a provider that does not * support creating asynchronous file channels, or an unsupported * open option is specified, or the array contains an attribute that * cannot be set atomically when creating the file * @throws IOException If an I/O error occurs * @throws SecurityException If a security manager is installed and it denies an * unspecified permission required by the implementation. * In the case of the default provider, the {@link SecurityManager#checkRead(String)} * method is invoked to check read access if the file is opened for reading. * The {@link SecurityManager#checkWrite(String)} method is invoked to check * write access if the file is opened for writing */ @Suspendable public static FiberFileChannel open(final ExecutorService ioExecutor, final Path path, final Set options, final FileAttribute... attrs) throws IOException { final ExecutorService ioExec = ioExecutor != null ? ioExecutor : fiberFileThreadPool; // FiberAsyncIO.ioExecutor(); // AsynchronousFileChannel afc = FiberAsyncIO.runBlockingIO(fiberFileThreadPool, new CheckedCallable() { @Override public AsynchronousFileChannel call() throws IOException { return AsynchronousFileChannel.open(path, options, ioExec, attrs); } }); return new FiberFileChannel(afc); } /** * Opens or creates a file for reading and/or writing, returning a file channel to access the file. * *

* An invocation of this method behaves in exactly the same way as the * invocation *

     *     ch.{@link #open(ExecutorService,Path,Set,FileAttribute[])
     *       open}(null, file, opts, new FileAttribute<?>[0]);
     * 
* where {@code opts} is a {@code Set} containing the options specified to * this method. * *

* The resulting channel is associated with default thread pool to which * tasks are submitted to handle I/O events and dispatch to completion * handlers that consume the result of asynchronous operations performed on * the resulting channel. * * @param path The path of the file to open or create * @param options Options specifying how the file is opened * * @return A new file channel * * @throws IllegalArgumentException If the set contains an invalid combination of options * @throws UnsupportedOperationException If the {@code file} is associated with a provider that does not * support creating file channels, or an unsupported open option is * specified * @throws IOException If an I/O error occurs * @throws SecurityException If a security manager is installed and it denies an * unspecified permission required by the implementation. * In the case of the default provider, the {@link SecurityManager#checkRead(String)} * method is invoked to check read access if the file is opened for reading. * The {@link SecurityManager#checkWrite(String)} method is invoked to check * write access if the file is opened for writing */ @Suspendable public static FiberFileChannel open(Path path, OpenOption... options) throws IOException { Set set = new HashSet(options.length); Collections.addAll(set, options); return open(null, path, set, NO_ATTRIBUTES); } @Override public final boolean isOpen() { return ac.isOpen(); } @Override @Suspendable public void close() throws IOException { ac.close(); FiberAsyncIO.runBlockingIO(fiberFileThreadPool, new CheckedCallable() { @Override public Void call() throws IOException { ac.close(); return null; } }); } @Override public long position() throws IOException { return position; } @Override public FiberFileChannel position(long newPosition) throws IOException { this.position = newPosition; return this; } /** * Reads a sequence of bytes from this channel into the given buffer, * starting at the given file position. * *

* This method works in the same manner as the {@link * #read(ByteBuffer)} method, except that bytes are read starting at the * given file position rather than at the channel's current position. This * method does not modify this channel's position. If the given position * is greater than the file's current size then no bytes are read.

* * @param dst * The buffer into which bytes are to be transferred * * @param position * The file position at which the transfer is to begin; * must be non-negative * * @return The number of bytes read, possibly zero, or {@code -1} if the * given position is greater than or equal to the file's current * size * * @throws IllegalArgumentException * If the position is negative * * @throws NonReadableChannelException * If this channel was not opened for reading * * @throws ClosedChannelException * If this channel is closed * * @throws AsynchronousCloseException * If another thread closes this channel * while the read operation is in progress * * @throws ClosedByInterruptException * If another thread interrupts the current thread * while the read operation is in progress, thereby * closing the channel and setting the current thread's * interrupt status * * @throws IOException * If some other I/O error occurs */ @Suspendable public int read(final ByteBuffer dst, final long position) throws IOException { return new FiberAsyncIO() { @Override protected void requestAsync() { ac.read(dst, position, null, makeCallback()); } }.runSneaky(); } @Override @Suspendable public int read(ByteBuffer dst) throws IOException { final int bytes = read(dst, position); position(position + bytes); return bytes; } /** * Reads a sequence of bytes from this channel into the given buffers. * *

* Bytes are read starting at this channel's current file position, and * then the file position is updated with the number of bytes actually * read. Otherwise this method behaves exactly as specified in the {@link * ScatteringByteChannel} interface.

*/ @Override @Suspendable public final long read(ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } @Override @Suspendable public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { long r = 0; for (int i = 0; i < length; i++) r += read(dsts[offset + i]); return r; } /** * Writes a sequence of bytes to this channel from the given buffer, * starting at the given file position. * *

* This method works in the same manner as the {@link * #write(ByteBuffer)} method, except that bytes are written starting at * the given file position rather than at the channel's current position. * This method does not modify this channel's position. If the given * position is greater than the file's current size then the file will be * grown to accommodate the new bytes; the values of any bytes between the * previous end-of-file and the newly-written bytes are unspecified.

* * @param src * The buffer from which bytes are to be transferred * * @param position * The file position at which the transfer is to begin; * must be non-negative * * @return The number of bytes written, possibly zero * * @throws IllegalArgumentException * If the position is negative * * @throws NonWritableChannelException * If this channel was not opened for writing * * @throws ClosedChannelException * If this channel is closed * * @throws AsynchronousCloseException * If another thread closes this channel * while the write operation is in progress * * @throws ClosedByInterruptException * If another thread interrupts the current thread * while the write operation is in progress, thereby * closing the channel and setting the current thread's * interrupt status * * @throws IOException * If some other I/O error occurs */ @Suspendable public int write(final ByteBuffer src, final long position) throws IOException { return new FiberAsyncIO() { @Override protected void requestAsync() { ac.write(src, position, null, makeCallback()); } }.runSneaky(); } @Override @Suspendable public int write(ByteBuffer src) throws IOException { final int bytes = write(src, position); position(position + bytes); return bytes; } @Override @Suspendable public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { long r = 0; for (int i = 0; i < length; i++) r += write(srcs[offset + i]); return r; } @Override @Suspendable public final long write(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } @Override public long size() throws IOException { return ac.size(); } @Suspendable public FileLock lock(final long position, final long size, final boolean shared) throws IOException { return new FiberAsyncIO() { @Override protected void requestAsync() { ac.lock(position, size, shared, null, makeCallback()); } }.runSneaky(); } public void force(boolean metaData) throws IOException { ac.force(metaData); } @Override public FiberFileChannel truncate(long size) throws IOException { ac.truncate(size); return this; } public FileLock tryLock(long position, long size, boolean shared) throws IOException { return ac.tryLock(position, size, shared); } public long transferTo(long position, long count, WritableByteChannel target) throws IOException { throw new UnsupportedOperationException(); } public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { throw new UnsupportedOperationException(); } public MappedByteBuffer map(FileChannel.MapMode mode, long position, long size) throws IOException { throw new UnsupportedOperationException(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy