8164900: Add support for O_DIRECT
Summary: Add support for Direct I/O in FileChannel
Reviewed-by: alanb, bpb, alanbur, coffeys, aph, clanger, plevart, mli, psandoz, simonis
Contributed-by: Lucy Lu <yingqi.lu@intel.com>, Volker Simonis <volker.simonis@gmail.com>
--- a/make/gensrc/GensrcMisc.gmk Fri Oct 20 11:08:18 2017 -0700
+++ b/make/gensrc/GensrcMisc.gmk Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,7 @@
define generate-preproc-src
$(call MakeDir, $(@D))
( $(NAWK) '/@@END_COPYRIGHT@@/{exit}1' $< && \
- $(CPP) $(CPP_FLAGS) $(SYSROOT_CFLAGS) $< \
+ $(CPP) $(CPP_FLAGS) $(SYSROOT_CFLAGS) $(CFLAGS_JDKLIB) $< \
2> >($(GREP) -v '^$(<F)$$' >&2) \
| $(NAWK) '/@@START_HERE@@/,0' \
| $(SED) -e 's/@@START_HERE@@/\/\/ AUTOMATICALLY GENERATED FILE - DO NOT EDIT/' \
--- a/make/jprt.properties Fri Oct 20 11:08:18 2017 -0700
+++ b/make/jprt.properties Tue Oct 17 16:51:11 2017 -0700
@@ -180,7 +180,8 @@
${my.make.rule.test.targets.hotspot.reg}, \
${my.make.rule.test.targets.hotspot.gtest} \
${my.make.rule.test.targets.nativesanity} \
- ${my.test.target.set:TESTNAME=jdk_lang}
+ ${my.test.target.set:TESTNAME=jdk_lang} \
+ ${my.test.target.set:TESTNAME=jdk_nio}
# 7155453: Work-around to prevent popups on OSX from blocking test completion
# but the work-around is added to all platforms to be consistent
--- a/make/mapfiles/libnio/mapfile-linux Fri Oct 20 11:08:18 2017 -0700
+++ b/make/mapfiles/libnio/mapfile-linux Tue Oct 17 16:51:11 2017 -0700
@@ -75,6 +75,7 @@
Java_sun_nio_ch_FileDispatcherImpl_truncate0;
Java_sun_nio_ch_FileDispatcherImpl_write0;
Java_sun_nio_ch_FileDispatcherImpl_writev0;
+ Java_sun_nio_ch_FileDispatcherImpl_setDirect0;
Java_sun_nio_ch_FileKey_init;
Java_sun_nio_ch_FileKey_initIDs;
Java_sun_nio_ch_InheritedChannel_close0;
--- a/make/mapfiles/libnio/mapfile-solaris Fri Oct 20 11:08:18 2017 -0700
+++ b/make/mapfiles/libnio/mapfile-solaris Tue Oct 17 16:51:11 2017 -0700
@@ -63,6 +63,7 @@
Java_sun_nio_ch_FileDispatcherImpl_truncate0;
Java_sun_nio_ch_FileDispatcherImpl_write0;
Java_sun_nio_ch_FileDispatcherImpl_writev0;
+ Java_sun_nio_ch_FileDispatcherImpl_setDirect0;
Java_sun_nio_ch_FileKey_init;
Java_sun_nio_ch_FileKey_initIDs;
Java_sun_nio_ch_InheritedChannel_close0;
--- a/make/test/JtregNativeJdk.gmk Fri Oct 20 11:08:18 2017 -0700
+++ b/make/test/JtregNativeJdk.gmk Tue Oct 17 16:51:11 2017 -0700
@@ -47,6 +47,10 @@
$(TOPDIR)/test/jdk/java/lang/String/nativeEncoding \
#
+ifneq ($(OPENJDK_TARGET_OS), windows)
+ BUILD_JDK_JTREG_NATIVE_SRC += $(TOPDIR)/test/jdk/java/nio/channels/FileChannel/directio
+endif
+
BUILD_JDK_JTREG_OUTPUT_DIR := $(OUTPUTDIR)/support/test/jdk/jtreg/native
BUILD_JDK_JTREG_IMAGE_DIR := $(TEST_IMAGE_DIR)/jdk/jtreg
@@ -56,8 +60,10 @@
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := $(WIN_LIB_JAVA)
else ifeq ($(OPENJDK_TARGET_OS), solaris)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava -lc
+ BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava -lc
else
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
+ BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
endif
$(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \
--- a/src/java.base/share/classes/java/nio/file/FileStore.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/java/nio/file/FileStore.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -112,6 +112,31 @@
public abstract long getUsableSpace() throws IOException;
/**
+ * Returns the number of bytes per block in this file store.
+ *
+ * <p> File storage is typically organized into discrete sequences of bytes
+ * called <i>blocks</i>. A block is the smallest storage unit of a file store.
+ * Every read and write operation is performed on a multiple of blocks.
+ *
+ * @implSpec The implementation in this class throws an
+ * {@code UnsupportedOperationException}.
+ *
+ * @return a positive value representing the block size of this file store,
+ * in bytes
+ *
+ * @throws IOException
+ * if an I/O error occurs
+ *
+ * @throws UnsupportedOperationException
+ * if the operation is not supported
+ *
+ * @since 10
+ */
+ public long getBlockSize() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Returns the number of unallocated bytes in the file store.
*
* <p> The returned number of unallocated bytes is a hint, but not a
--- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java Tue Oct 17 16:51:11 2017 -0700
@@ -41,6 +41,11 @@
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystemException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@@ -87,6 +92,12 @@
// Positional-read is not interruptible
private volatile boolean uninterruptible;
+ // DirectIO flag
+ private final boolean direct;
+
+ // IO alignment value for DirectIO
+ private final int alignment;
+
// Cleanable with an action which closes this channel's file descriptor
private final Cleanable closer;
@@ -103,14 +114,22 @@
}
private FileChannelImpl(FileDescriptor fd, String path, boolean readable,
- boolean writable, Object parent)
+ boolean writable, boolean direct, Object parent)
{
this.fd = fd;
this.readable = readable;
this.writable = writable;
this.parent = parent;
this.path = path;
+ this.direct = direct;
this.nd = new FileDispatcherImpl();
+ if (direct) {
+ assert path != null;
+ this.alignment = nd.setDirectIO(fd, path);
+ } else {
+ this.alignment = -1;
+ }
+
// Register a cleaning action if and only if there is no parent
// as the parent will take care of closing the file descriptor.
// FileChannel is used by the LambdaMetaFactory so a lambda cannot
@@ -125,7 +144,14 @@
boolean readable, boolean writable,
Object parent)
{
- return new FileChannelImpl(fd, path, readable, writable, parent);
+ return new FileChannelImpl(fd, path, readable, writable, false, parent);
+ }
+
+ public static FileChannel open(FileDescriptor fd, String path,
+ boolean readable, boolean writable,
+ boolean direct, Object parent)
+ {
+ return new FileChannelImpl(fd, path, readable, writable, direct, parent);
}
private void ensureOpen() throws IOException {
@@ -181,6 +207,8 @@
if (!readable)
throw new NonReadableChannelException();
synchronized (positionLock) {
+ if (direct)
+ Util.checkChannelPositionAligned(position(), alignment);
int n = 0;
int ti = -1;
try {
@@ -189,7 +217,7 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.read(fd, dst, -1, nd);
+ n = IOUtil.read(fd, dst, -1, direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -209,6 +237,8 @@
if (!readable)
throw new NonReadableChannelException();
synchronized (positionLock) {
+ if (direct)
+ Util.checkChannelPositionAligned(position(), alignment);
long n = 0;
int ti = -1;
try {
@@ -217,7 +247,8 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.read(fd, dsts, offset, length, nd);
+ n = IOUtil.read(fd, dsts, offset, length,
+ direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -233,6 +264,8 @@
if (!writable)
throw new NonWritableChannelException();
synchronized (positionLock) {
+ if (direct)
+ Util.checkChannelPositionAligned(position(), alignment);
int n = 0;
int ti = -1;
try {
@@ -241,7 +274,7 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.write(fd, src, -1, nd);
+ n = IOUtil.write(fd, src, -1, direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -261,6 +294,8 @@
if (!writable)
throw new NonWritableChannelException();
synchronized (positionLock) {
+ if (direct)
+ Util.checkChannelPositionAligned(position(), alignment);
long n = 0;
int ti = -1;
try {
@@ -269,7 +304,8 @@
if (!isOpen())
return 0;
do {
- n = IOUtil.write(fd, srcs, offset, length, nd);
+ n = IOUtil.write(fd, srcs, offset, length,
+ direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -752,6 +788,8 @@
throw new IllegalArgumentException("Negative position");
if (!readable)
throw new NonReadableChannelException();
+ if (direct)
+ Util.checkChannelPositionAligned(position, alignment);
ensureOpen();
if (nd.needsPositionLock()) {
synchronized (positionLock) {
@@ -774,7 +812,7 @@
if (!isOpen())
return -1;
do {
- n = IOUtil.read(fd, dst, position, nd);
+ n = IOUtil.read(fd, dst, position, direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
@@ -791,6 +829,8 @@
throw new IllegalArgumentException("Negative position");
if (!writable)
throw new NonWritableChannelException();
+ if (direct)
+ Util.checkChannelPositionAligned(position, alignment);
ensureOpen();
if (nd.needsPositionLock()) {
synchronized (positionLock) {
@@ -811,7 +851,7 @@
if (!isOpen())
return -1;
do {
- n = IOUtil.write(fd, src, position, nd);
+ n = IOUtil.write(fd, src, position, direct, alignment, nd);
} while ((n == IOStatus.INTERRUPTED) && isOpen());
return IOStatus.normalize(n);
} finally {
--- a/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/FileDispatcher.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,4 +61,6 @@
abstract boolean canTransferToDirectly(SelectableChannel sc);
abstract boolean transferToDirectlyNeedsPositionLock();
+
+ abstract int setDirectIO(FileDescriptor fd, String path);
}
--- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,22 +47,38 @@
NativeDispatcher nd)
throws IOException
{
- if (src instanceof DirectBuffer)
- return writeFromNativeBuffer(fd, src, position, nd);
+ return write(fd, src, position, false, -1, nd);
+ }
+
+ static int write(FileDescriptor fd, ByteBuffer src, long position,
+ boolean directIO, int alignment, NativeDispatcher nd)
+ throws IOException
+ {
+ if (src instanceof DirectBuffer) {
+ return writeFromNativeBuffer(fd, src, position,
+ directIO, alignment, nd);
+ }
// Substitute a native buffer
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
- ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+ ByteBuffer bb;
+ if (directIO) {
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+ bb = Util.getTemporaryAlignedDirectBuffer(rem, alignment);
+ } else {
+ bb = Util.getTemporaryDirectBuffer(rem);
+ }
try {
bb.put(src);
bb.flip();
// Do not update src until we see how many bytes were written
src.position(pos);
- int n = writeFromNativeBuffer(fd, bb, position, nd);
+ int n = writeFromNativeBuffer(fd, bb, position,
+ directIO, alignment, nd);
if (n > 0) {
// now update src
src.position(pos + n);
@@ -74,7 +90,8 @@
}
private static int writeFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
- long position, NativeDispatcher nd)
+ long position, boolean directIO,
+ int alignment, NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
@@ -82,6 +99,11 @@
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
+ if (directIO) {
+ Util.checkBufferPositionAligned(bb, pos, alignment);
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+ }
+
int written = 0;
if (rem == 0)
return 0;
@@ -100,13 +122,20 @@
static long write(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
- return write(fd, bufs, 0, bufs.length, nd);
+ return write(fd, bufs, 0, bufs.length, false, -1, nd);
}
static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
+ return write(fd, bufs, offset, length, false, -1, nd);
+ }
+
+ static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+ boolean directIO, int alignment, NativeDispatcher nd)
+ throws IOException
+ {
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false;
@@ -122,12 +151,20 @@
int lim = buf.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
+ if (directIO)
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+
if (rem > 0) {
vec.setBuffer(iov_len, buf, pos, rem);
// allocate shadow buffer to ensure I/O is done with direct buffer
if (!(buf instanceof DirectBuffer)) {
- ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+ ByteBuffer shadow;
+ if (directIO)
+ shadow = Util.getTemporaryAlignedDirectBuffer(rem,
+ alignment);
+ else
+ shadow = Util.getTemporaryDirectBuffer(rem);
shadow.put(buf);
shadow.flip();
vec.setShadow(iov_len, shadow);
@@ -186,15 +223,32 @@
NativeDispatcher nd)
throws IOException
{
+ return read(fd, dst, position, false, -1, nd);
+ }
+
+ static int read(FileDescriptor fd, ByteBuffer dst, long position,
+ boolean directIO, int alignment, NativeDispatcher nd)
+ throws IOException
+ {
if (dst.isReadOnly())
throw new IllegalArgumentException("Read-only buffer");
if (dst instanceof DirectBuffer)
- return readIntoNativeBuffer(fd, dst, position, nd);
+ return readIntoNativeBuffer(fd, dst, position,
+ directIO, alignment, nd);
// Substitute a native buffer
- ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
+ ByteBuffer bb;
+ int rem = dst.remaining();
+ if (directIO) {
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+ bb = Util.getTemporaryAlignedDirectBuffer(rem,
+ alignment);
+ } else {
+ bb = Util.getTemporaryDirectBuffer(rem);
+ }
try {
- int n = readIntoNativeBuffer(fd, bb, position, nd);
+ int n = readIntoNativeBuffer(fd, bb, position,
+ directIO, alignment,nd);
bb.flip();
if (n > 0)
dst.put(bb);
@@ -205,7 +259,8 @@
}
private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
- long position, NativeDispatcher nd)
+ long position, boolean directIO,
+ int alignment, NativeDispatcher nd)
throws IOException
{
int pos = bb.position();
@@ -213,6 +268,11 @@
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
+ if (directIO) {
+ Util.checkBufferPositionAligned(bb, pos, alignment);
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+ }
+
if (rem == 0)
return 0;
int n = 0;
@@ -230,13 +290,20 @@
static long read(FileDescriptor fd, ByteBuffer[] bufs, NativeDispatcher nd)
throws IOException
{
- return read(fd, bufs, 0, bufs.length, nd);
+ return read(fd, bufs, 0, bufs.length, false, -1, nd);
}
static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
NativeDispatcher nd)
throws IOException
{
+ return read(fd, bufs, offset, bufs.length, false, -1, nd);
+ }
+
+ static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,
+ boolean directIO, int alignment, NativeDispatcher nd)
+ throws IOException
+ {
IOVecWrapper vec = IOVecWrapper.get(length);
boolean completed = false;
@@ -255,12 +322,21 @@
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
+ if (directIO)
+ Util.checkRemainingBufferSizeAligned(rem, alignment);
+
if (rem > 0) {
vec.setBuffer(iov_len, buf, pos, rem);
// allocate shadow buffer to ensure I/O is done with direct buffer
if (!(buf instanceof DirectBuffer)) {
- ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem);
+ ByteBuffer shadow;
+ if (directIO) {
+ shadow = Util.getTemporaryAlignedDirectBuffer(rem,
+ alignment);
+ } else {
+ shadow = Util.getTemporaryDirectBuffer(rem);
+ }
vec.setShadow(iov_len, shadow);
buf = shadow;
pos = shadow.position();
--- a/src/java.base/share/classes/sun/nio/ch/Util.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/ch/Util.java Tue Oct 17 16:51:11 2017 -0700
@@ -37,7 +37,7 @@
import java.util.Set;
import jdk.internal.misc.Unsafe;
import sun.security.action.GetPropertyAction;
-
+import java.io.IOException;
public class Util {
@@ -237,6 +237,33 @@
}
/**
+ * Returns a temporary buffer of at least the given size and
+ * aligned to the alignment
+ */
+ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
+ int alignment) {
+ if (isBufferTooLarge(size)) {
+ return ByteBuffer.allocateDirect(size + alignment - 1)
+ .alignedSlice(alignment);
+ }
+
+ BufferCache cache = bufferCache.get();
+ ByteBuffer buf = cache.get(size);
+ if (buf != null) {
+ if (buf.alignmentOffset(0, alignment) == 0) {
+ return buf;
+ }
+ } else {
+ if (!cache.isEmpty()) {
+ buf = cache.removeFirst();
+ free(buf);
+ }
+ }
+ return ByteBuffer.allocateDirect(size + alignment - 1)
+ .alignedSlice(alignment);
+ }
+
+ /**
* Releases a temporary buffer by returning to the cache or freeing it.
*/
public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
@@ -459,4 +486,37 @@
}
return dbb;
}
+
+ static void checkBufferPositionAligned(ByteBuffer bb,
+ int pos, int alignment)
+ throws IOException
+ {
+ if (bb.alignmentOffset(pos, alignment) != 0) {
+ throw new IOException("Current location of the bytebuffer ("
+ + pos + ") is not a multiple of the block size ("
+ + alignment + ")");
+ }
+ }
+
+ static void checkRemainingBufferSizeAligned(int rem,
+ int alignment)
+ throws IOException
+ {
+ if (rem % alignment != 0) {
+ throw new IOException("Number of remaining bytes ("
+ + rem + ") is not a multiple of the block size ("
+ + alignment + ")");
+ }
+ }
+
+ static void checkChannelPositionAligned(long position,
+ int alignment)
+ throws IOException
+ {
+ if (position % alignment != 0) {
+ throw new IOException("Channel position (" + position
+ + ") is not a multiple of the block size ("
+ + alignment + ")");
+ }
+ }
}
--- a/src/java.base/share/classes/sun/nio/fs/ExtendedOptions.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/share/classes/sun/nio/fs/ExtendedOptions.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -137,6 +137,8 @@
public static final InternalOption<Void> FILE_TREE = new InternalOption<>();
+ public static final InternalOption<Void> DIRECT = new InternalOption<>();
+
public static final InternalOption<Integer> SENSITIVITY_HIGH = new InternalOption<>();
public static final InternalOption<Integer> SENSITIVITY_MEDIUM = new InternalOption<>();
public static final InternalOption<Integer> SENSITIVITY_LOW = new InternalOption<>();
--- a/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/ch/FileDispatcherImpl.java Tue Oct 17 16:51:11 2017 -0700
@@ -122,6 +122,17 @@
return false;
}
+ int setDirectIO(FileDescriptor fd, String path) {
+ int result = -1;
+ try {
+ result = setDirect0(fd);
+ } catch (IOException e) {
+ throw new UnsupportedOperationException
+ ("Error setting up DirectIO", e);
+ }
+ return result;
+ }
+
// -- Native methods --
static native int read0(FileDescriptor fd, long address, int len)
@@ -167,6 +178,8 @@
static native void closeIntFD(int fd) throws IOException;
+ static native int setDirect0(FileDescriptor fd) throws IOException;
+
static native void init();
}
--- a/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixChannelFactory.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,7 @@
boolean deleteOnClose;
boolean sync;
boolean dsync;
+ boolean direct;
static Flags toFlags(Set<? extends OpenOption> options) {
Flags flags = new Flags();
@@ -88,6 +89,12 @@
flags.noFollowLinks = true;
continue;
}
+
+ if (ExtendedOptions.DIRECT.matches(option)) {
+ flags.direct = true;
+ continue;
+ }
+
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException(option + " not supported");
@@ -134,7 +141,8 @@
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
- return FileChannelImpl.open(fdObj, path.toString(), flags.read, flags.write, null);
+ return FileChannelImpl.open(fdObj, path.toString(), flags.read,
+ flags.write, flags.direct, null);
}
/**
@@ -235,6 +243,8 @@
oflags |= O_DSYNC;
if (flags.sync)
oflags |= O_SYNC;
+ if (flags.direct)
+ oflags |= O_DIRECT;
// permission check before we open the file
SecurityManager sm = System.getSecurityManager();
--- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -70,6 +70,12 @@
static final int PREFIX_O_NOFOLLOW = 00;
#endif
+#ifdef O_DIRECT
+ static final int PREFIX_O_DIRECT = O_DIRECT;
+#else
+ // not supported (dummy values will not be used at runtime).
+ static final int PREFIX_O_DIRECT = 00;
+#endif
static final int PREFIX_S_IAMB =
(S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
--- a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -126,6 +126,12 @@
}
@Override
+ public long getBlockSize() throws IOException {
+ UnixFileStoreAttributes attrs = readAttributes();
+ return attrs.blockSize();
+ }
+
+ @Override
public long getUnallocatedSpace() throws IOException {
UnixFileStoreAttributes attrs = readAttributes();
return attrs.blockSize() * attrs.freeBlocks();
--- a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c Tue Oct 17 16:51:11 2017 -0700
@@ -50,7 +50,7 @@
#define mmap64 mmap
#endif
-static jfieldID chan_fd; /* jobject 'fd' in sun.io.FileChannelImpl */
+static jfieldID chan_fd; /* jobject 'fd' in sun.nio.ch.FileChannelImpl */
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileChannelImpl_initIDs(JNIEnv *env, jclass clazz)
--- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Tue Oct 17 16:51:11 2017 -0700
@@ -34,6 +34,7 @@
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
+#include <sys/statvfs.h>
#if defined(__linux__)
#include <linux/fs.h>
#include <sys/ioctl.h>
@@ -323,3 +324,58 @@
{
closeFileDescriptor(env, fd);
}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass clazz,
+ jobject fdo)
+{
+ jint fd = fdval(env, fdo);
+ jint result;
+#ifdef MACOSX
+ struct statvfs file_stat;
+#else
+ struct statvfs64 file_stat;
+#endif
+
+#if defined(O_DIRECT) || defined(F_NOCACHE) || defined(DIRECTIO_ON)
+#ifdef O_DIRECT
+ jint orig_flag;
+ orig_flag = fcntl(fd, F_GETFL);
+ if (orig_flag == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ return -1;
+ }
+ result = fcntl(fd, F_SETFL, orig_flag | O_DIRECT);
+ if (result == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ return result;
+ }
+#elif F_NOCACHE
+ result = fcntl(fd, F_NOCACHE, 1);
+ if (result == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ return result;
+ }
+#elif DIRECTIO_ON
+ result = directio(fd, DIRECTIO_ON);
+ if (result == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ return result;
+ }
+#endif
+#ifdef MACOSX
+ result = fstatvfs(fd, &file_stat);
+#else
+ result = fstatvfs64(fd, &file_stat);
+#endif
+ if(result == -1) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ return result;
+ } else {
+ result = (int)file_stat.f_frsize;
+ }
+#else
+ result == -1;
+#endif
+ return result;
+}
--- a/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java Tue Oct 17 16:51:11 2017 -0700
@@ -30,6 +30,8 @@
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
import sun.security.action.GetPropertyAction;
+import java.io.File;
+import java.nio.CharBuffer;
class FileDispatcherImpl extends FileDispatcher {
@@ -123,6 +125,21 @@
return true;
}
+ int setDirectIO(FileDescriptor fd, String path)
+ {
+ int result = -1;
+ String filePath = path.substring(0, path.lastIndexOf(File.separator));
+ CharBuffer buffer = CharBuffer.allocate(filePath.length());
+ buffer.put(filePath);
+ try {
+ result = setDirect0(fd, buffer);
+ } catch (IOException e) {
+ throw new UnsupportedOperationException
+ ("Error setting up DirectIO", e);
+ }
+ return result;
+ }
+
static boolean isFastFileTransferRequested() {
String fileTransferProp = GetPropertyAction
.privilegedGetProperty("jdk.nio.enableFastFileTransfer");
@@ -177,4 +194,6 @@
static native void close0(FileDescriptor fd) throws IOException;
static native long duplicateHandle(long fd) throws IOException;
+
+ static native int setDirect0(FileDescriptor fd, CharBuffer buffer) throws IOException;
}
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,7 @@
boolean overlapped;
boolean sync;
boolean dsync;
+ boolean direct;
// non-standard
boolean shareRead = true;
@@ -121,6 +122,10 @@
flags.shareDelete = false;
continue;
}
+ if (ExtendedOptions.DIRECT.matches(option)) {
+ flags.direct = true;
+ continue;
+ }
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException();
@@ -161,7 +166,8 @@
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
- return FileChannelImpl.open(fdObj, pathForWindows, flags.read, flags.write, null);
+ return FileChannelImpl.open(fdObj, pathForWindows, flags.read,
+ flags.write, flags.direct, null);
}
/**
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -125,9 +125,18 @@
}
// read the free space info
+ private DiskFreeSpace readDiskFreeSpaceEx() throws IOException {
+ try {
+ return GetDiskFreeSpaceEx(root);
+ } catch (WindowsException x) {
+ x.rethrowAsIOException(root);
+ return null;
+ }
+ }
+
private DiskFreeSpace readDiskFreeSpace() throws IOException {
try {
- return GetDiskFreeSpaceEx(root);
+ return GetDiskFreeSpace(root);
} catch (WindowsException x) {
x.rethrowAsIOException(root);
return null;
@@ -136,17 +145,21 @@
@Override
public long getTotalSpace() throws IOException {
- return readDiskFreeSpace().totalNumberOfBytes();
+ return readDiskFreeSpaceEx().totalNumberOfBytes();
}
@Override
public long getUsableSpace() throws IOException {
- return readDiskFreeSpace().freeBytesAvailable();
+ return readDiskFreeSpaceEx().freeBytesAvailable();
+ }
+
+ public long getBlockSize() throws IOException {
+ return readDiskFreeSpace().bytesPerSector();
}
@Override
public long getUnallocatedSpace() throws IOException {
- return readDiskFreeSpace().freeBytesAvailable();
+ return readDiskFreeSpaceEx().freeBytesAvailable();
}
@Override
@@ -165,6 +178,8 @@
return getUsableSpace();
if (attribute.equals("unallocatedSpace"))
return getUnallocatedSpace();
+ if (attribute.equals("bytesPerSector"))
+ return getBlockSize();
// windows specific for testing purposes
if (attribute.equals("volume:vsn"))
return volInfo.volumeSerialNumber();
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -485,21 +485,50 @@
buffer.release();
}
}
+
+ /**
+ * GetDiskFreeSpace(
+ * LPCTSTR lpRootPathName,
+ * LPDWORD lpSectorsPerCluster,
+ * LPDWORD lpBytesPerSector,
+ * LPDWORD lpNumberOfFreeClusters,
+ * LPDWORD lpTotalNumberOfClusters
+ * )
+ */
+ static DiskFreeSpace GetDiskFreeSpace(String path)
+ throws WindowsException
+ {
+ NativeBuffer buffer = asNativeBuffer(path);
+ try {
+ DiskFreeSpace space = new DiskFreeSpace();
+ GetDiskFreeSpace0(buffer.address(), space);
+ return space;
+ } finally {
+ buffer.release();
+ }
+ }
+
static class DiskFreeSpace {
private long freeBytesAvailable;
private long totalNumberOfBytes;
private long totalNumberOfFreeBytes;
+ private long bytesPerSector;
private DiskFreeSpace() { }
public long freeBytesAvailable() { return freeBytesAvailable; }
public long totalNumberOfBytes() { return totalNumberOfBytes; }
public long totalNumberOfFreeBytes() { return totalNumberOfFreeBytes; }
+ public long bytesPerSector() { return bytesPerSector; }
}
private static native void GetDiskFreeSpaceEx0(long lpDirectoryName,
DiskFreeSpace obj)
throws WindowsException;
+ private static native void GetDiskFreeSpace0(long lpRootPathName,
+ DiskFreeSpace obj)
+ throws WindowsException;
+
/**
* GetVolumePathName(
* LPCTSTR lpszFileName,
--- a/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/native/libnio/ch/FileDispatcherImpl.c Tue Oct 17 16:51:11 2017 -0700
@@ -456,3 +456,33 @@
JNU_ThrowIOExceptionWithLastError(env, "DuplicateHandle failed");
return ptr_to_jlong(hResult);
}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_setDirect0(JNIEnv *env, jclass this,
+ jobject fdObj, jobject buffer)
+{
+ jint result = -1;
+
+ HANDLE orig = (HANDLE)(handleval(env, fdObj));
+
+ HANDLE modify = ReOpenFile(orig, 0, 0,
+ FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH);
+
+ if (modify != INVALID_HANDLE_VALUE) {
+ DWORD sectorsPerCluster;
+ DWORD bytesPerSector;
+ DWORD numberOfFreeClusters;
+ DWORD totalNumberOfClusters;
+ LPCWSTR lpRootPathName = (*env)->GetDirectBufferAddress(env, buffer);
+ BOOL res = GetDiskFreeSpaceW(lpRootPathName,
+ §orsPerCluster,
+ &bytesPerSector,
+ &numberOfFreeClusters,
+ &totalNumberOfClusters);
+ if (res == 0) {
+ JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
+ }
+ result = bytesPerSector;
+ }
+ return result;
+}
--- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c Fri Oct 20 11:08:18 2017 -0700
+++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,6 +59,8 @@
static jfieldID diskSpace_totalBytes;
static jfieldID diskSpace_totalFree;
+static jfieldID diskSpace_bytesPerSector;
+
static jfieldID account_domain;
static jfieldID account_name;
static jfieldID account_use;
@@ -121,6 +123,8 @@
CHECK_NULL(diskSpace_totalBytes);
diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J");
CHECK_NULL(diskSpace_totalFree);
+ diskSpace_bytesPerSector = (*env)->GetFieldID(env, clazz, "bytesPerSector", "J");
+ CHECK_NULL(diskSpace_bytesPerSector);
clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account");
CHECK_NULL(clazz);
@@ -582,6 +586,30 @@
long_to_jlong(totalNumberOfFreeBytes.QuadPart));
}
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetDiskFreeSpace0(JNIEnv* env, jclass this,
+ jlong address, jobject obj)
+{
+ DWORD sectorsPerCluster;
+ DWORD bytesPerSector;
+ DWORD numberOfFreeClusters;
+ DWORD totalNumberOfClusters;
+ LPCWSTR lpRootPathName = jlong_to_ptr(address);
+
+
+ BOOL res = GetDiskFreeSpaceW(lpRootPathName,
+ §orsPerCluster,
+ &bytesPerSector,
+ &numberOfFreeClusters,
+ &totalNumberOfClusters);
+ if (res == 0) {
+ throwWindowsException(env, GetLastError());
+ return;
+ }
+
+ (*env)->SetLongField(env, obj, diskSpace_bytesPerSector,
+ long_to_jlong(bytesPerSector));
+}
JNIEXPORT jstring JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumePathName0(JNIEnv* env, jclass this,
--- a/src/jdk.unsupported/share/classes/com/sun/nio/file/ExtendedOpenOption.java Fri Oct 20 11:08:18 2017 -0700
+++ b/src/jdk.unsupported/share/classes/com/sun/nio/file/ExtendedOpenOption.java Tue Oct 17 16:51:11 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,29 @@
/**
* Prevent operations on the file that request delete access.
*/
- NOSHARE_DELETE(ExtendedOptions.NOSHARE_DELETE);
+ NOSHARE_DELETE(ExtendedOptions.NOSHARE_DELETE),
+
+ /**
+ * Requires that direct I/O be used for read or write access.
+ * Attempting to open a file with this option set will result in
+ * an {@code UnsupportedOperationException} if the operating system or
+ * file system does not support Direct I/O or a sufficient equivalent.
+ *
+ * @apiNote
+ * The DIRECT option enables performing file I/O directly between user
+ * buffers and the file thereby circumventing the operating system page
+ * cache and possibly avoiding the thrashing which could otherwise occur
+ * in I/O-intensive applications. This option may be of benefit to
+ * applications which do their own caching or do random I/O operations
+ * on large data sets. It is likely to provide the most benefit when
+ * the file is stored on a device which has high I/O throughput capacity.
+ * The option should be used with caution however as in general it is
+ * likely to degrade performance. The performance effects of using it
+ * should be evaluated in each particular circumstance.
+ *
+ * @since 10
+ */
+ DIRECT(ExtendedOptions.DIRECT);
ExtendedOpenOption(ExtendedOptions.InternalOption<Void> option) {
option.register(this);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8164900
+ * @summary Test for ExtendedOpenOption.DIRECT flag
+ * @requires (os.family == "linux" | os.family == "solaris"
+ * | os.family == "aix")
+ * @library /test/lib
+ * @build jdk.test.lib.Platform
+ * @run main/native DirectIOTest
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.nio.file.Path;
+import java.nio.file.Files;
+import jdk.test.lib.Platform;
+import java.nio.file.FileStore;
+import java.nio.file.StandardOpenOption;
+import com.sun.nio.file.ExtendedOpenOption;
+
+public class DirectIOTest {
+
+ private static final int SIZE = 4096;
+
+ private static void testWrite(Path p) throws Exception {
+ try (FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE,
+ ExtendedOpenOption.DIRECT)) {
+ FileStore fs = Files.getFileStore(p);
+ int alignment = (int)fs.getBlockSize();
+ ByteBuffer src = ByteBuffer.allocateDirect(SIZE + alignment - 1)
+ .alignedSlice(alignment);
+ for (int j = 0; j < SIZE; j++) {
+ src.put((byte)0);
+ }
+ src.flip();
+ fc.write(src);
+ }
+ }
+
+ private static void testRead(Path p) throws Exception {
+ try (FileChannel fc = FileChannel.open(p, ExtendedOpenOption.DIRECT)) {
+ FileStore fs = Files.getFileStore(p);
+ int alignment = (int)fs.getBlockSize();
+ ByteBuffer dest = ByteBuffer.allocateDirect(SIZE + alignment - 1)
+ .alignedSlice(alignment);
+ fc.read(dest);
+ }
+ }
+
+ public static Path createTempFile() throws IOException {
+ return Files.createTempFile(
+ Paths.get(System.getProperty("test.dir", ".")), "test", null);
+ }
+
+ public static boolean isDirectIOSupportedByFS(Path p) throws Exception {
+ boolean supported = true;
+ if (Platform.isSolaris()) {
+ String fsType = Files.getFileStore(p).type();
+ if (!fsType.equals("nfs") && !fsType.equals("ufs")) {
+ // print a message and return without failing
+ System.out.format("Skipping test: file system type %s of "
+ + "FileStore of %s is neither nfs nor ufs.%n", fsType, p);
+ supported = false;
+ }
+ }
+ return supported;
+ }
+
+ private static boolean isFileInCache(Path p) {
+ String path = p.toString();
+ return isFileInCache0(SIZE, path);
+ }
+
+ private static native boolean isFileInCache0(int size, String path);
+
+ public static void main(String[] args) throws Exception {
+ Path p = createTempFile();
+
+ if (!isDirectIOSupportedByFS(p)) {
+ Files.delete(p);
+ return;
+ }
+
+ System.loadLibrary("DirectIO");
+
+ try {
+ testWrite(p);
+ if (isFileInCache(p)) {
+ throw new RuntimeException("DirectIO is not working properly with "
+ + "write. File still exists in cache!");
+ }
+ testRead(p);
+ if (isFileInCache(p)) {
+ throw new RuntimeException("DirectIO is not working properly with "
+ + "read. File still exists in cache!");
+ }
+ } finally {
+ Files.delete(p);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/PreadDirect.java Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test positional read method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * DirectIOTest
+ * @run main/othervm PreadDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+/**
+ * Testing FileChannel's positional read method.
+ */
+
+public class PreadDirect {
+
+ private static PrintStream err = System.err;
+
+ private static Random generator = RandomFactory.getRandom();
+
+ private static int charsPerGroup = -1;
+
+ private static int alignment = -1;
+
+ public static void main(String[] args) throws Exception {
+ if (initTests()) {
+ genericTest();
+ testNotAlignedChannelPosition();
+ testNegativeChannelPosition();
+ }
+ }
+
+ private static boolean initTests() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+ Files.delete(p);
+ return false;
+ }
+ try {
+ FileStore fs = Files.getFileStore(p);
+ alignment = (int)fs.getBlockSize();
+ charsPerGroup = alignment;
+ } finally {
+ Files.delete(p);
+ }
+ return true;
+ }
+
+ private static void testNegativeChannelPosition() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ fos.write(new byte[charsPerGroup]);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ try {
+ fc.read(ByteBuffer.allocate(charsPerGroup), -1L);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch(IllegalArgumentException e) {
+ // Correct result
+ }
+ }
+ }
+
+ private static void testNotAlignedChannelPosition() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ fos.write(new byte[charsPerGroup]);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ long pos = charsPerGroup - 1;
+ try {
+ fc.read(ByteBuffer.allocate(charsPerGroup), pos);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch(IOException e) {
+ if (!e.getMessage().contains("Channel position (" + pos
+ + ") is not a multiple of the block size (" + alignment + ")"))
+ throw new RuntimeException("Read test failed");
+ }
+ }
+ }
+
+ private static void genericTest() throws Exception {
+ StringBuffer sb = new StringBuffer();
+ sb.setLength(2);
+
+ Path p = DirectIOTest.createTempFile();
+
+ initTestFile(p);
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block =
+ ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+ .alignedSlice(alignment);
+ for (int x = 0; x < 100; x++) {
+ block.clear();
+ long offset = generator.nextInt(100) * charsPerGroup;
+ long expectedResult = offset / charsPerGroup;
+ offset = expectedResult * charsPerGroup;
+
+ long originalPosition = fc.position();
+
+ int read = fc.read(block, offset);
+ if (read != charsPerGroup)
+ throw new Exception("Read failed");
+
+ long newPosition = fc.position();
+
+ for (int i = 0; i < 2; i++) {
+ byte aByte = block.get(i);
+ sb.setCharAt(i, (char)aByte);
+ }
+ int result = Integer.parseInt(sb.toString());
+ if (result != expectedResult) {
+ err.println("I expected "+ expectedResult);
+ err.println("I got "+ result);
+ throw new Exception("Read test failed");
+ }
+
+ // Ensure that file pointer position has not changed
+ if (originalPosition != newPosition)
+ throw new Exception("File position modified");
+ }
+ }
+ }
+
+ private static void initTestFile(Path p) throws Exception {
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ try (BufferedWriter awriter
+ = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+
+ for (int i = 0; i < 100; i++) {
+ String number = new Integer(i).toString();
+ for (int h = 0; h < 2 - number.length(); h++)
+ awriter.write("0");
+ awriter.write(""+i);
+ for (int j = 0; j < (charsPerGroup - 2); j++)
+ awriter.write("0");
+ }
+ awriter.flush();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/PwriteDirect.java Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test positional write method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * DirectIOTest
+ * @run main/othervm PwriteDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+/**
+ * Testing FileChannel's positional write method.
+ */
+public class PwriteDirect {
+
+ private static Random generator = RandomFactory.getRandom();
+
+ private static int charsPerGroup = -1;
+
+ private static int alignment = -1;
+
+ private static boolean initTests() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+ Files.delete(p);
+ return false;
+ }
+ try {
+ FileStore fs = Files.getFileStore(p);
+ alignment = (int)fs.getBlockSize();
+ charsPerGroup = alignment;
+ } finally {
+ Files.delete(p);
+ }
+ return true;
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (initTests()) {
+ genericTest();
+ TestWithNotAlignedChannelPosition();
+ testUnwritableChannel();
+ }
+ }
+
+ private static void testUnwritableChannel() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ try {
+ fc.write(ByteBuffer.allocate(charsPerGroup), 0);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch(NonWritableChannelException e) {
+ // Correct result
+ }
+ }
+ }
+
+ private static void TestWithNotAlignedChannelPosition() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ int bufferSize = charsPerGroup;
+ long position = charsPerGroup - 1;
+ try {
+ fc.write(ByteBuffer.allocate(bufferSize), position);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch(IOException e) {
+ if (!e.getMessage().contains("Channel position (" + position + ")"
+ + " is not a multiple of the block size (" + alignment + ")"))
+ throw new RuntimeException("Write test failed");
+ }
+ }
+ }
+
+ private static void genericTest() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+
+ initTestFile(p);
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.WRITE,
+ StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block =
+ ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+ .alignedSlice(alignment);
+ for (int x = 0; x < 100; x++) {
+ block.clear();
+ long offset = generator.nextInt(100) * charsPerGroup;
+
+ // Write known sequence out
+ for (int i = 0; i < charsPerGroup; i++) {
+ block.put(i, (byte)'a');
+ }
+ long originalPosition = fc.position();
+
+ int written = fc.write(block, offset);
+ if (written < 0)
+ throw new Exception("Write failed");
+
+ long newPosition = fc.position();
+
+ // Ensure that file pointer position has not changed
+ if (originalPosition != newPosition)
+ throw new Exception("File position modified");
+
+ // Attempt to read sequence back in
+ originalPosition = fc.position();
+
+ block.rewind();
+ int read = fc.read(block, offset);
+ if (read != charsPerGroup)
+ throw new Exception("Read failed");
+
+ newPosition = fc.position();
+
+ // Ensure that file pointer position has not changed
+ if (originalPosition != newPosition)
+ throw new Exception("File position modified");
+
+ for (int j = 0; j < charsPerGroup; j++) {
+ if (block.get(j) != (byte)'a')
+ throw new Exception("Write test failed");
+ }
+ }
+ }
+ }
+
+ private static void initTestFile(Path p) throws Exception {
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ try (BufferedWriter awriter
+ = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+ for (int i = 0; i < 100; i++) {
+ String number = new Integer(i).toString();
+ for (int h = 0; h < 4 - number.length(); h++)
+ awriter.write("0");
+ awriter.write("" + i);
+ for (int j = 0; j < 4092; j++)
+ awriter.write("0");
+ }
+ awriter.flush();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/ReadDirect.java Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8164900
+ * @summary Test read method of FileChannel with DirectIO
+ * (use -Dseed=X to set PRNG seed)
+ * @library .. /test/lib
+ * @build jdk.test.lib.RandomFactory
+ * DirectIOTest
+ * @run main/othervm ReadDirect
+ * @key randomness
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Random;
+import com.sun.nio.file.ExtendedOpenOption;
+
+import jdk.test.lib.RandomFactory;
+
+public class ReadDirect {
+
+ private static PrintStream err = System.err;
+
+ private static Random generator = RandomFactory.getRandom();
+
+ private static int charsPerGroup = -1;
+
+ private static int alignment = -1;
+
+ private static boolean initTests() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+ Files.delete(p);
+ return false;
+ }
+ try {
+ FileStore fs = Files.getFileStore(p);
+ alignment = (int)fs.getBlockSize();
+ charsPerGroup = alignment;
+ } finally {
+ Files.delete(p);
+ }
+ return true;
+ }
+
+ private static void testWithSingleBuffer() throws Exception {
+ StringBuffer sb = new StringBuffer();
+ sb.setLength(2);
+
+ Path p = DirectIOTest.createTempFile();
+
+ initTestFile(p);
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block = ByteBuffer.allocateDirect(charsPerGroup
+ + alignment - 1).alignedSlice(alignment);
+ for (int x = 0; x < 100; x++) {
+ block.clear();
+ long offset = x * charsPerGroup;
+ long expectedResult = offset / charsPerGroup;
+ fc.read(block);
+
+ for (int i = 0; i < 2; i++) {
+ byte aByte = block.get(i);
+ sb.setCharAt(i, (char)aByte);
+ }
+ int result = Integer.parseInt(sb.toString());
+ if (result != expectedResult) {
+ err.println("I expected " + expectedResult);
+ err.println("I got " + result);
+ throw new Exception("Read test failed");
+ }
+ }
+ }
+ }
+
+ private static void testWithNotAlignedBufferSize() throws Exception {
+ int bufferSize = charsPerGroup - 1;
+ Path p = DirectIOTest.createTempFile();
+
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ fos.write(new byte[bufferSize]);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block = ByteBuffer.allocate(bufferSize);
+ try {
+ fc.read(block);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch (IOException e) {
+ if (!e.getMessage().contains("Number of remaining bytes ("
+ + bufferSize + ") is not a multiple of the block size ("
+ + alignment + ")"))
+ throw new Exception("Read test failed");
+ }
+ }
+ }
+
+ private static void testWithNotAlignedBufferOffset() throws Exception {
+ int bufferSize = charsPerGroup * 2;
+ int pos = alignment - 1;
+
+ Path p = DirectIOTest.createTempFile();
+
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ fos.write(new byte[bufferSize]);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block = ByteBuffer.allocateDirect(bufferSize);
+ block.position(pos);
+ block.limit(bufferSize - 1);
+ try {
+ fc.read(block);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch (IOException e) {
+ if (!e.getMessage().contains("Current location of the bytebuffer "
+ + "(" + pos + ") is not a multiple of the block size ("
+ + alignment + ")"))
+ throw new Exception("Read test failed");
+ }
+ }
+ }
+
+ private static void testWithArrayOfBuffer() throws Exception {
+ StringBuffer sb = new StringBuffer();
+ sb.setLength(2);
+ ByteBuffer[] dests = new ByteBuffer[4];
+ Path p = DirectIOTest.createTempFile();
+
+ initTestFile(p);
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ int randomNumber = -1;
+
+ for (int i = 0; i < 4; i++) {
+ dests[i] = ByteBuffer.allocateDirect
+ (charsPerGroup + alignment - 1).alignedSlice(alignment);
+ for (int j = 0; j < charsPerGroup; j++) {
+ dests[i].put(j, (byte)'a');
+ }
+ }
+
+ randomNumber = generator.nextInt(100);
+ long offset = randomNumber * charsPerGroup;
+ fc.position(offset);
+ fc.read(dests, 1, 2);
+
+ for (int i = 0; i < 4; i++) {
+ if (i == 1 || i == 2) {
+ for (int j = 0; j < 2; j++) {
+ byte aByte = dests[i].get(j);
+ sb.setCharAt(j, (char)aByte);
+ }
+ int result = Integer.parseInt(sb.toString());
+ int expectedResult = randomNumber + i - 1;
+ if (result != expectedResult) {
+ err.println("I expected " + expectedResult);
+ err.println("I got " + result);
+ throw new Exception("Read test failed");
+ }
+ } else {
+ for (int k = 0; k < charsPerGroup; k++) {
+ if (dests[i].get(k) != (byte)'a')
+ throw new RuntimeException("Read test failed");
+ }
+ }
+ }
+ }
+ }
+
+ public static void testOnEOF() throws Exception {
+ int bufferSize = charsPerGroup / 2;
+ Path p = DirectIOTest.createTempFile();
+
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ byte[] writeBlock = new byte[bufferSize];
+ for (int i = 0; i < bufferSize; i++) {
+ writeBlock[i] = ((byte)'a');
+ }
+ fos.write(writeBlock);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block = ByteBuffer.allocateDirect(
+ (bufferSize / alignment + 1) * alignment + alignment - 1)
+ .alignedSlice(alignment);
+ int result = fc.read(block);
+ if (result != bufferSize) {
+ err.println("Number of bytes to read " + bufferSize);
+ err.println("I read " + result);
+ throw new Exception("Read test failed");
+ }
+ for (int j = 0; j < bufferSize; j++) {
+ if (block.get(j) != (byte)'a')
+ throw new RuntimeException("Read test failed");
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (initTests()) {
+ testWithSingleBuffer();
+ testWithNotAlignedBufferSize();
+ testWithNotAlignedBufferOffset();
+ testWithArrayOfBuffer();
+ testOnEOF();
+ }
+ }
+
+ private static void initTestFile(Path p)
+ throws Exception {
+ try (OutputStream fos = Files.newOutputStream(p)) {
+ try (BufferedWriter awriter
+ = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
+ for (int i = 0; i < 100; i++) {
+ String number = new Integer(i).toString();
+ for (int h = 0; h < 2 - number.length(); h++)
+ awriter.write("0");
+ awriter.write("" + i);
+ for (int j = 0; j < (charsPerGroup - 2); j++)
+ awriter.write("0");
+ }
+ awriter.flush();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/WriteDirect.java Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8164900
+ * @summary Test FileChannel write with DirectIO
+ * @library .. /test/lib
+ * @build DirectIOTest
+ * @run main/othervm WriteDirect
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import com.sun.nio.file.ExtendedOpenOption;
+
+public class WriteDirect {
+
+ private static int charsPerGroup = -1;
+
+ private static int alignment = -1;
+
+ private static boolean initTests() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
+ Files.delete(p);
+ return false;
+ }
+ try {
+ FileStore fs = Files.getFileStore(p);
+ alignment = (int)fs.getBlockSize();
+ charsPerGroup = alignment;
+ } finally {
+ Files.delete(p);
+ }
+ return true;
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (initTests()) {
+ testWithNotAlignedBuffer();
+ testWithNotAlignedBufferOffset();
+ testWithArrayOfBuffer();
+ }
+ }
+
+ static void testWithNotAlignedBuffer() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ int bufferSize = charsPerGroup - 1;
+ ByteBuffer src = ByteBuffer.allocate(bufferSize);
+ try {
+ fc.write(src);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch (IOException e) {
+ if (!e.getMessage().contains("Number of remaining bytes ("
+ + bufferSize + ") is not a multiple of the block size ("
+ + alignment + ")"))
+ throw new Exception("Write failure");
+ }
+ }
+ }
+
+ private static void testWithNotAlignedBufferOffset() throws Exception {
+ int bufferSize = charsPerGroup * 2;
+ int pos = alignment - 1;
+
+ Path p = DirectIOTest.createTempFile();
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE,
+ ExtendedOpenOption.DIRECT)) {
+ ByteBuffer block = ByteBuffer.allocateDirect(bufferSize);
+ block.position(pos);
+ block.limit(bufferSize - 1);
+ try {
+ fc.write(block);
+ throw new RuntimeException("Expected exception not thrown");
+ } catch (IOException e) {
+ if (!e.getMessage().contains("Current location of the bytebuffer "
+ + "(" + pos + ") is not a multiple of the block size ("
+ + alignment + ")"))
+ throw new Exception("Write test failed");
+ }
+ }
+ }
+
+ static void testWithArrayOfBuffer() throws Exception {
+ Path p = DirectIOTest.createTempFile();
+ ByteBuffer[] srcs = new ByteBuffer[4];
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.WRITE, ExtendedOpenOption.DIRECT)) {
+ for (int i = 0; i < 4; i++) {
+ srcs[i] = ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
+ .alignedSlice(alignment);
+ for (int j = 0; j < charsPerGroup; j++) {
+ srcs[i].put((byte)i);
+ }
+ srcs[i].flip();
+ }
+
+ fc.write(srcs, 1, 2);
+ }
+
+ try (FileChannel fc = FileChannel.open(p,
+ StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE)) {
+ ByteBuffer bb = ByteBuffer.allocateDirect(charsPerGroup * 2);
+ fc.read(bb);
+ bb.flip();
+ for (int k = 0; k < charsPerGroup; k++) {
+ if (bb.get() != 1)
+ throw new RuntimeException("Write failure");
+ }
+ for (int m = 0; m < charsPerGroup; m++) {
+ if (bb.get() != 2)
+ throw new RuntimeException("Write failure");
+ }
+ try {
+ bb.get();
+ throw new RuntimeException("Write failure");
+ } catch (BufferUnderflowException bufe) {
+ // correct result
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c Tue Oct 17 16:51:11 2017 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Test if a file exists in the file system cache
+ */
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "jni.h"
+
+/*
+ * Throws an exception with the given class name and detail message
+ */
+static void ThrowException(JNIEnv *env, const char *name, const char *msg) {
+ jclass cls = (*env)->FindClass(env, name);
+ if (cls != NULL) {
+ (*env)->ThrowNew(env, cls, msg);
+ }
+}
+
+/*
+ * Class: DirectIO
+ * Method: isFileInCache0
+ * Signature: (ILjava/lang/String;)Z
+ */
+JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env,
+ jclass cls,
+ jint file_size,
+ jstring file_path) {
+ void *f_mmap;
+#ifdef __linux__
+ unsigned char *f_seg;
+#else
+ char *f_seg;
+#endif
+
+#ifdef __APPLE__
+ size_t mask = MINCORE_INCORE;
+#else
+ size_t mask = 0x1;
+#endif
+
+ size_t page_size = getpagesize();
+ size_t index = (file_size + page_size - 1) /page_size;
+ jboolean result = JNI_FALSE;
+
+ const char* path = (*env)->GetStringUTFChars(env, file_path, JNI_FALSE);
+
+ int fd = open(path, O_RDWR);
+
+ (*env)->ReleaseStringUTFChars(env, file_path, path);
+
+ f_mmap = mmap(0, file_size, PROT_NONE, MAP_SHARED, fd, 0);
+ if (f_mmap == MAP_FAILED) {
+ close(fd);
+ ThrowException(env, "java/io/IOException",
+ "test of whether file exists in cache failed");
+ }
+ f_seg = malloc(index);
+ if (f_seg != NULL) {
+ if(mincore(f_mmap, file_size, f_seg) == 0) {
+ size_t i;
+ for (i = 0; i < index; i++) {
+ if (f_seg[i] & mask) {
+ result = JNI_TRUE;
+ break;
+ }
+ }
+ }
+ free(f_seg);
+ } else {
+ ThrowException(env, "java/io/IOException",
+ "test of whether file exists in cache failed");
+ }
+ close(fd);
+ munmap(f_mmap, file_size);
+ return result;
+}