mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8164900: Add support for O_DIRECT
Add support for Direct I/O in FileChannel Co-authored-by: Volker Simonis <volker.simonis@gmail.com> Reviewed-by: alanb, bpb, alanbur, coffeys, aph, clanger, plevart, mli, psandoz, simonis
This commit is contained in:
parent
97db013bd3
commit
ec1c3bce45
30 changed files with 1523 additions and 45 deletions
|
@ -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
|
||||
|
@ -111,6 +111,31 @@ public abstract class FileStore {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -41,6 +41,11 @@ import java.nio.channels.OverlappingFileLockException;
|
|||
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 @@ public class FileChannelImpl
|
|||
// 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 @@ public class FileChannelImpl
|
|||
}
|
||||
|
||||
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 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
if (!readable)
|
||||
throw new NonReadableChannelException();
|
||||
synchronized (positionLock) {
|
||||
if (direct)
|
||||
Util.checkChannelPositionAligned(position(), alignment);
|
||||
int n = 0;
|
||||
int ti = -1;
|
||||
try {
|
||||
|
@ -189,7 +217,7 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
if (!readable)
|
||||
throw new NonReadableChannelException();
|
||||
synchronized (positionLock) {
|
||||
if (direct)
|
||||
Util.checkChannelPositionAligned(position(), alignment);
|
||||
long n = 0;
|
||||
int ti = -1;
|
||||
try {
|
||||
|
@ -217,7 +247,8 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
if (!writable)
|
||||
throw new NonWritableChannelException();
|
||||
synchronized (positionLock) {
|
||||
if (direct)
|
||||
Util.checkChannelPositionAligned(position(), alignment);
|
||||
int n = 0;
|
||||
int ti = -1;
|
||||
try {
|
||||
|
@ -241,7 +274,7 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
if (!writable)
|
||||
throw new NonWritableChannelException();
|
||||
synchronized (positionLock) {
|
||||
if (direct)
|
||||
Util.checkChannelPositionAligned(position(), alignment);
|
||||
long n = 0;
|
||||
int ti = -1;
|
||||
try {
|
||||
|
@ -269,7 +304,8 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
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 @@ public class FileChannelImpl
|
|||
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 {
|
||||
|
|
|
@ -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 class FileDispatcher extends NativeDispatcher {
|
|||
abstract boolean canTransferToDirectly(SelectableChannel sc);
|
||||
|
||||
abstract boolean transferToDirectlyNeedsPositionLock();
|
||||
|
||||
abstract int setDirectIO(FileDescriptor fd, String path);
|
||||
}
|
||||
|
|
|
@ -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 @@ public class IOUtil {
|
|||
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 @@ public class IOUtil {
|
|||
}
|
||||
|
||||
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 @@ public class IOUtil {
|
|||
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,12 +122,19 @@ public class IOUtil {
|
|||
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);
|
||||
|
||||
|
@ -122,12 +151,20 @@ public class IOUtil {
|
|||
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);
|
||||
|
@ -185,16 +222,33 @@ public class IOUtil {
|
|||
static int read(FileDescriptor fd, ByteBuffer dst, long position,
|
||||
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 @@ public class IOUtil {
|
|||
}
|
||||
|
||||
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 @@ public class IOUtil {
|
|||
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,12 +290,19 @@ public class IOUtil {
|
|||
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);
|
||||
|
||||
|
@ -255,12 +322,21 @@ public class IOUtil {
|
|||
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();
|
||||
|
|
|
@ -37,7 +37,7 @@ import java.util.Iterator;
|
|||
import java.util.Set;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Util {
|
||||
|
||||
|
@ -236,6 +236,33 @@ public class Util {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -459,4 +486,37 @@ public class Util {
|
|||
}
|
||||
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 + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 final class ExtendedOptions {
|
|||
|
||||
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<>();
|
||||
|
|
|
@ -122,6 +122,17 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
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 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
|
||||
static native void closeIntFD(int fd) throws IOException;
|
||||
|
||||
static native int setDirect0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native void init();
|
||||
|
||||
}
|
||||
|
|
|
@ -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 @@ class UnixChannelFactory {
|
|||
boolean deleteOnClose;
|
||||
boolean sync;
|
||||
boolean dsync;
|
||||
boolean direct;
|
||||
|
||||
static Flags toFlags(Set<? extends OpenOption> options) {
|
||||
Flags flags = new Flags();
|
||||
|
@ -88,6 +89,12 @@ class UnixChannelFactory {
|
|||
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 @@ class UnixChannelFactory {
|
|||
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 @@ class UnixChannelFactory {
|
|||
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();
|
||||
|
|
|
@ -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 @@ class UnixConstants {
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
|
@ -125,6 +125,12 @@ abstract class UnixFileStore
|
|||
return attrs.blockSize() * attrs.availableBlocks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBlockSize() throws IOException {
|
||||
UnixFileStoreAttributes attrs = readAttributes();
|
||||
return attrs.blockSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnallocatedSpace() throws IOException {
|
||||
UnixFileStoreAttributes attrs = readAttributes();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import java.io.IOException;
|
|||
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 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
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 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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 @@ class WindowsChannelFactory {
|
|||
boolean overlapped;
|
||||
boolean sync;
|
||||
boolean dsync;
|
||||
boolean direct;
|
||||
|
||||
// non-standard
|
||||
boolean shareRead = true;
|
||||
|
@ -121,6 +122,10 @@ class WindowsChannelFactory {
|
|||
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 @@ class WindowsChannelFactory {
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,7 +125,7 @@ class WindowsFileStore
|
|||
}
|
||||
|
||||
// read the free space info
|
||||
private DiskFreeSpace readDiskFreeSpace() throws IOException {
|
||||
private DiskFreeSpace readDiskFreeSpaceEx() throws IOException {
|
||||
try {
|
||||
return GetDiskFreeSpaceEx(root);
|
||||
} catch (WindowsException x) {
|
||||
|
@ -134,19 +134,32 @@ class WindowsFileStore
|
|||
}
|
||||
}
|
||||
|
||||
private DiskFreeSpace readDiskFreeSpace() throws IOException {
|
||||
try {
|
||||
return GetDiskFreeSpace(root);
|
||||
} catch (WindowsException x) {
|
||||
x.rethrowAsIOException(root);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@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 @@ class WindowsFileStore
|
|||
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();
|
||||
|
|
|
@ -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 @@ class WindowsNativeDispatcher {
|
|||
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,
|
||||
|
|
|
@ -456,3 +456,33 @@ Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlo
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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_bytesAvailable;
|
|||
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 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
|
|||
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 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetDiskFreeSpaceEx0(JNIEnv* env, jclass
|
|||
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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue