--- old/src/java.base/share/classes/java/io/FileOutputStream.java 2016-08-25 17:51:52.726564686 -0700 +++ new/src/java.base/share/classes/java/io/FileOutputStream.java 2016-08-25 17:51:52.624564685 -0700 @@ -79,6 +79,10 @@ private final AtomicBoolean closed = new AtomicBoolean(false); + private boolean direct = false; + + private int pageSize = -1; + /** * Creates a file output stream to write to the file with the * specified name. A new FileDescriptor object is @@ -101,7 +105,7 @@ * @see java.lang.SecurityManager#checkWrite(java.lang.String) */ public FileOutputStream(String name) throws FileNotFoundException { - this(name != null ? new File(name) : null, false); + this(name != null ? new File(name) : null, false, false); } /** @@ -133,7 +137,42 @@ public FileOutputStream(String name, boolean append) throws FileNotFoundException { - this(name != null ? new File(name) : null, append); + this(name != null ? new File(name) : null, append, false); + } + + /** + * Creates a file output stream to write to the file with the specified + * name. If the second argument is true, then bytes will + * be written to the end of the file rather than the beginning. If the + * third parameter is true, then bytes will be directly + * written to storage media. A new FileDescriptor object + * is created to represent this file connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with name as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param name the system-dependent file name + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @param direct if true, then bytes will be written + * directly to storage media + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason. + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since 1.9 + */ + public FileOutputStream(String name, boolean append, boolean direct) + throws FileNotFoundException + { + this(name != null ? new File(name) : null, append, direct); } /** @@ -162,7 +201,7 @@ * @see java.lang.SecurityManager#checkWrite(java.lang.String) */ public FileOutputStream(File file) throws FileNotFoundException { - this(file, false); + this(file, false, false); } /** @@ -197,6 +236,49 @@ public FileOutputStream(File file, boolean append) throws FileNotFoundException { + this(file, append, false); + } + + /** + * Creates a file output stream to write to the file represented by + * the specified File object. If the second argument is + * true, then bytes will be written to the end of the file + * rather than the beginning. If the third argument is true, + * then bytes will be directly written to storage media. A new + * FileDescriptor object is created to represent this file + * connection. + *

+ * First, if there is a security manager, its checkWrite + * method is called with the path represented by the file + * argument as its argument. + *

+ * If the file exists but is a directory rather than a regular file, does + * not exist but cannot be created, or cannot be opened for any other + * reason then a FileNotFoundException is thrown. + * + * @param file the file to be opened for writing. + * @param append if true, then bytes will be written + * to the end of the file rather than the beginning + * @param direct if true, then bytes will be written + * directly to storage media + * @exception FileNotFoundException if the file exists but is a directory + * rather than a regular file, does not exist but cannot + * be created, or cannot be opened for any other reason + * @exception SecurityException if a security manager exists and its + * checkWrite method denies write access + * to the file. + * @see java.io.File#getPath() + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkWrite(java.lang.String) + * @since 1.9 + */ + public FileOutputStream(File file, boolean append, boolean direct) + throws FileNotFoundException + { + this.direct = direct; + if (direct) { + getPageSize(); + } String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -256,8 +338,9 @@ * Opens a file, with the specified name, for overwriting or appending. * @param name name of file to be opened * @param append whether the file is to be opened in append mode + * @param direct whether the file s to be opened in the direct mode */ - private native void open0(String name, boolean append) + private native void open0(String name, boolean append, boolean direct) throws FileNotFoundException; // wrap native call to allow instrumentation @@ -268,7 +351,16 @@ */ private void open(String name, boolean append) throws FileNotFoundException { - open0(name, append); + open0(name, append, direct); + } + + private native int getPageSize0(); + + private int getPageSize() { + if (pageSize == -1) { + pageSize = getPageSize0(); + } + return this.pageSize; } /** @@ -304,6 +396,17 @@ throws IOException; /** + * Writes a sub array as a sequence of bytes with DirectIO. + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param append {@code true} to first advance the position to the + * end of file + * @exception IOException If an I/O error has occurred.*/ + private native void writeBytesD(byte b[], int off, int len, boolean append) + throws IOException; + + /** * Writes b.length bytes from the specified byte array * to this file output stream. * @@ -311,7 +414,15 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[]) throws IOException { - writeBytes(b, 0, b.length, fdAccess.getAppend(fd)); + if (direct) { + if((b.length % pageSize != 0) ||(getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size must be aligned " + + "with kernel page size " + pageSize + " bytes!"); + } + writeBytesD(b, 0, b.length, fdAccess.getAppend(fd)); + } else { + writeBytes(b, 0, b.length, fdAccess.getAppend(fd)); + } } /** @@ -324,9 +435,23 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { - writeBytes(b, off, len, fdAccess.getAppend(fd)); + if (direct) { + if((len % pageSize != 0) || (getCurrentLocation() % pageSize != 0)) { + throw new IOException("In DirectIO mode, the IO size and the start " + + "point must be aligned with kernel page size " + pageSize + " bytes!"); + } + writeBytesD(b, off, len, fdAccess.getAppend(fd)); + } else { + writeBytes(b, off, len, fdAccess.getAppend(fd)); + } + } + + private long getCurrentLocation() throws IOException { + return getCurrentLocation0(); } + private native long getCurrentLocation0() throws IOException; + /** * Closes this file output stream and releases any system resources * associated with this stream. This file output stream may no longer