8224974: Implement JEP 352

Non-Volatile Mapped Byte Buffers

Reviewed-by: alanb, kvn, bpb, gromero, darcy, shade, bulasevich, dchuyko
This commit is contained in:
Andrew Dinn 2019-08-20 10:11:53 +01:00
parent db359f11b5
commit 047b8bfeb7
53 changed files with 1400 additions and 69 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, 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
@ -46,6 +46,8 @@ import java.nio.channels.WritableByteChannel;
import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.ExtendedMapMode;
import jdk.internal.misc.Unsafe;
import jdk.internal.ref.Cleaner;
import jdk.internal.ref.CleanerFactory;
@ -860,20 +862,15 @@ public class FileChannelImpl
// -- Memory-mapped buffers --
private static class Unmapper
private static abstract class Unmapper
implements Runnable
{
// may be required to close file
private static final NativeDispatcher nd = new FileDispatcherImpl();
// keep track of mapped buffer usage
static volatile int count;
static volatile long totalSize;
static volatile long totalCapacity;
private volatile long address;
private final long size;
private final int cap;
protected final long size;
protected final int cap;
private final FileDescriptor fd;
private Unmapper(long address, long size, int cap,
@ -884,12 +881,6 @@ public class FileChannelImpl
this.size = size;
this.cap = cap;
this.fd = fd;
synchronized (Unmapper.class) {
count++;
totalSize += size;
totalCapacity += cap;
}
}
public void run() {
@ -907,7 +898,63 @@ public class FileChannelImpl
}
}
synchronized (Unmapper.class) {
decrementStats();
}
protected abstract void incrementStats();
protected abstract void decrementStats();
}
private static class DefaultUnmapper extends Unmapper {
// keep track of non-sync mapped buffer usage
static volatile int count;
static volatile long totalSize;
static volatile long totalCapacity;
public DefaultUnmapper(long address, long size, int cap,
FileDescriptor fd) {
super(address, size, cap, fd);
incrementStats();
}
protected void incrementStats() {
synchronized (DefaultUnmapper.class) {
count++;
totalSize += size;
totalCapacity += cap;
}
}
protected void decrementStats() {
synchronized (DefaultUnmapper.class) {
count--;
totalSize -= size;
totalCapacity -= cap;
}
}
}
private static class SyncUnmapper extends Unmapper {
// keep track of mapped buffer usage
static volatile int count;
static volatile long totalSize;
static volatile long totalCapacity;
public SyncUnmapper(long address, long size, int cap,
FileDescriptor fd) {
super(address, size, cap, fd);
incrementStats();
}
protected void incrementStats() {
synchronized (SyncUnmapper.class) {
count++;
totalSize += size;
totalCapacity += cap;
}
}
protected void decrementStats() {
synchronized (SyncUnmapper.class) {
count--;
totalSize -= size;
totalCapacity -= cap;
@ -941,18 +988,30 @@ public class FileChannelImpl
throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
int imode;
boolean isSync = false;
if (mode == MapMode.READ_ONLY)
imode = MAP_RO;
else if (mode == MapMode.READ_WRITE)
imode = MAP_RW;
else if (mode == MapMode.PRIVATE)
imode = MAP_PV;
else
else if (mode == ExtendedMapMode.READ_ONLY_SYNC) {
imode = MAP_RO;
isSync = true;
} else if (mode == ExtendedMapMode.READ_WRITE_SYNC) {
imode = MAP_RW;
isSync = true;
} else {
throw new UnsupportedOperationException();
if ((mode != MapMode.READ_ONLY) && !writable)
}
if ((mode != MapMode.READ_ONLY) && mode != ExtendedMapMode.READ_ONLY_SYNC && !writable)
throw new NonWritableChannelException();
if (!readable)
throw new NonReadableChannelException();
// reject SYNC request if writeback is not enabled for this platform
if (isSync && !Unsafe.isWritebackEnabled()) {
throw new UnsupportedOperationException();
}
long addr = -1;
int ti = -1;
@ -990,9 +1049,9 @@ public class FileChannelImpl
// a valid file descriptor is not required
FileDescriptor dummy = new FileDescriptor();
if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(0, 0, dummy, null);
return Util.newMappedByteBufferR(0, 0, dummy, null, isSync);
else
return Util.newMappedByteBuffer(0, 0, dummy, null);
return Util.newMappedByteBuffer(0, 0, dummy, null, isSync);
}
pagePosition = (int)(position % allocationGranularity);
@ -1000,7 +1059,7 @@ public class FileChannelImpl
mapSize = size + pagePosition;
try {
// If map0 did not throw an exception, the address is valid
addr = map0(imode, mapPosition, mapSize);
addr = map0(imode, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted
// memory so force gc and re-attempt map
@ -1011,7 +1070,7 @@ public class FileChannelImpl
Thread.currentThread().interrupt();
}
try {
addr = map0(imode, mapPosition, mapSize);
addr = map0(imode, mapPosition, mapSize, isSync);
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
@ -1032,17 +1091,21 @@ public class FileChannelImpl
assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0);
int isize = (int)size;
Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
Unmapper um = (isSync
? new SyncUnmapper(addr, mapSize, isize, mfd)
: new DefaultUnmapper(addr, mapSize, isize, mfd));
if ((!writable) || (imode == MAP_RO)) {
return Util.newMappedByteBufferR(isize,
addr + pagePosition,
mfd,
um);
um,
isSync);
} else {
return Util.newMappedByteBuffer(isize,
addr + pagePosition,
mfd,
um);
um,
isSync);
}
} finally {
threads.remove(ti);
@ -1062,15 +1125,40 @@ public class FileChannelImpl
}
@Override
public long getCount() {
return Unmapper.count;
return DefaultUnmapper.count;
}
@Override
public long getTotalCapacity() {
return Unmapper.totalCapacity;
return DefaultUnmapper.totalCapacity;
}
@Override
public long getMemoryUsed() {
return Unmapper.totalSize;
return DefaultUnmapper.totalSize;
}
};
}
/**
* Invoked by sun.management.ManagementFactoryHelper to create the management
* interface for sync mapped buffers.
*/
public static JavaNioAccess.BufferPool getSyncMappedBufferPool() {
return new JavaNioAccess.BufferPool() {
@Override
public String getName() {
return "mapped - 'non-volatile memory'";
}
@Override
public long getCount() {
return SyncUnmapper.count;
}
@Override
public long getTotalCapacity() {
return SyncUnmapper.totalCapacity;
}
@Override
public long getMemoryUsed() {
return SyncUnmapper.totalSize;
}
};
}
@ -1196,7 +1284,7 @@ public class FileChannelImpl
// -- Native methods --
// Creates a new mapping
private native long map0(int prot, long position, long length)
private native long map0(int prot, long position, long length, boolean isSync)
throws IOException;
// Removes an existing mapping