Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 64 additions & 26 deletions test/jdk/java/nio/channels/FileChannel/directio/DirectIOTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
* @summary Test for ExtendedOpenOption.DIRECT flag
* @requires (os.family == "linux" | os.family == "aix")
* @library /test/lib
* @modules java.base/sun.nio.ch:+open java.base/java.io:+open
* @build jdk.test.lib.Platform
* @run main/native DirectIOTest
*/

import java.io.*;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
Expand All @@ -47,10 +49,25 @@
public class DirectIOTest {

private static final int BASE_SIZE = 4096;
private static final int TRIES = 3;

public static int getFD(FileChannel channel) throws Exception {
Field fFdFd = channel.getClass().getDeclaredField("fd");
fFdFd.setAccessible(true);
FileDescriptor fd = (FileDescriptor) fFdFd.get(channel);

Field fFd = FileDescriptor.class.getDeclaredField("fd");
fFd.setAccessible(true);
return fFd.getInt(fd);
}

private static void testWrite(Path p, long blockSize) throws Exception {
try (FileChannel fc = FileChannel.open(p,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
ExtendedOpenOption.DIRECT)) {
int fd = getFD(fc);

private static int testWrite(Path p, long blockSize) throws Exception {
try (FileChannel fc = FileChannel.open(p, StandardOpenOption.WRITE,
ExtendedOpenOption.DIRECT)) {
int bs = (int)blockSize;
int size = Math.max(BASE_SIZE, bs);
int alignment = bs;
Expand All @@ -60,22 +77,55 @@ private static int testWrite(Path p, long blockSize) throws Exception {
for (int j = 0; j < size; j++) {
src.put((byte)0);
}
src.flip();
fc.write(src);
return size;

// If there is AV or other FS tracing software, it may cache the file
// contents on first access, even though we have asked for DIRECT here.
// Do several attempts to make test more resilient.

for (int t = 0; t < TRIES; t++) {
flushFileCache(size, fd);
src.flip();
fc.position(0);
fc.write(src);
if (!isFileInCache(size, fd)) {
return;
}
}

throw new RuntimeException("DirectIO is not working properly with " +
"write. File still exists in cache!");
}
}

private static int testRead(Path p, long blockSize) throws Exception {
try (FileChannel fc = FileChannel.open(p, ExtendedOpenOption.DIRECT)) {
private static void testRead(Path p, long blockSize) throws Exception {
try (FileChannel fc = FileChannel.open(p,
StandardOpenOption.READ,
ExtendedOpenOption.DIRECT)) {
int fd = getFD(fc);

int bs = (int)blockSize;
int size = Math.max(BASE_SIZE, bs);
int alignment = bs;
ByteBuffer dest = ByteBuffer.allocateDirect(size + alignment - 1)
.alignedSlice(alignment);
assert dest.capacity() != 0;
fc.read(dest);
return size;

// If there is AV or other FS tracing software, it may cache the file
// contents on first access, even though we have asked for DIRECT here.
// Do several attempts to make test more resilient.

for (int t = 0; t < TRIES; t++) {
flushFileCache(size, fd);
dest.clear();
fc.position(0);
fc.read(dest);
if (!isFileInCache(size, fd)) {
return;
}
}

throw new RuntimeException("DirectIO is not working properly with " +
"read. File still exists in cache!");
}
}

Expand All @@ -84,12 +134,8 @@ public static Path createTempFile() throws IOException {
Paths.get(System.getProperty("test.dir", ".")), "test", null);
}

private static boolean isFileInCache(int size, Path p) {
String path = p.toString();
return isFileInCache0(size, path);
}

private static native boolean isFileInCache0(int size, String path);
private static native boolean flushFileCache(int size, int fd);
private static native boolean isFileInCache(int size, int fd);

public static void main(String[] args) throws Exception {
Path p = createTempFile();
Expand All @@ -98,16 +144,8 @@ public static void main(String[] args) throws Exception {
System.loadLibrary("DirectIO");

try {
int size = testWrite(p, blockSize);
if (isFileInCache(size, p)) {
throw new RuntimeException("DirectIO is not working properly with "
+ "write. File still exists in cache!");
}
size = testRead(p, blockSize);
if (isFileInCache(size, p)) {
throw new RuntimeException("DirectIO is not working properly with "
+ "read. File still exists in cache!");
}
testWrite(p, blockSize);
testRead(p, blockSize);
} finally {
Files.delete(p);
}
Expand Down
34 changes: 20 additions & 14 deletions test/jdk/java/nio/channels/FileChannel/directio/libDirectIO.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,27 @@ static void ThrowException(JNIEnv *env, const char *name, const char *msg) {

/*
* Class: DirectIO
* Method: isFileInCache0
* Signature: (ILjava/lang/String;)Z
* Method: flushFileCache
* Signature: (II;)V
*/
JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env,
JNIEXPORT void Java_DirectIOTest_flushFileCache(JNIEnv *env,
jclass cls,
jint file_size,
jstring file_path) {
jint fd) {
#ifdef __linux__
posix_fadvise(fd, 0, file_size, POSIX_FADV_DONTNEED);
#endif
}

/*
* Class: DirectIO
* Method: isFileInCache
* Signature: (II;)Z
*/
JNIEXPORT jboolean Java_DirectIOTest_isFileInCache(JNIEnv *env,
jclass cls,
jint file_size,
jint fd) {
void *f_mmap;
#ifdef __linux__
unsigned char *f_seg;
Expand All @@ -69,17 +83,10 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env,
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");
"test of whether file exists in cache failed: mmap failed");
}
f_seg = malloc(index);
if (f_seg != NULL) {
Expand All @@ -95,9 +102,8 @@ JNIEXPORT jboolean Java_DirectIOTest_isFileInCache0(JNIEnv *env,
free(f_seg);
} else {
ThrowException(env, "java/io/IOException",
"test of whether file exists in cache failed");
"test of whether file exists in cache failed: malloc failed");
}
close(fd);
munmap(f_mmap, file_size);
return result;
}