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:
Lucy Lu 2017-10-17 16:51:11 -07:00 committed by Brian Burkhalter
parent 97db013bd3
commit ec1c3bce45
30 changed files with 1523 additions and 45 deletions

View file

@ -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;
}

View file

@ -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);
}
/**

View file

@ -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();

View file

@ -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,

View file

@ -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,
&sectorsPerCluster,
&bytesPerSector,
&numberOfFreeClusters,
&totalNumberOfClusters);
if (res == 0) {
JNU_ThrowIOExceptionWithLastError(env, "DirectIO setup failed");
}
result = bytesPerSector;
}
return result;
}

View file

@ -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,
&sectorsPerCluster,
&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,