/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.nio;
import java.io.
FileDescriptor;
import sun.misc.
Unsafe;
/**
* A direct byte buffer whose content is a memory-mapped region of a file.
*
* <p> Mapped byte buffers are created via the {@link
* java.nio.channels.FileChannel#map FileChannel.map} method. This class
* extends the {@link ByteBuffer} class with operations that are specific to
* memory-mapped file regions.
*
* <p> A mapped byte buffer and the file mapping that it represents remain
* valid until the buffer itself is garbage-collected.
*
* <p> The content of a mapped byte buffer can change at any time, for example
* if the content of the corresponding region of the mapped file is changed by
* this program or another. Whether or not such changes occur, and when they
* occur, is operating-system dependent and therefore unspecified.
*
* <a name="inaccess"></a><p> All or part of a mapped byte buffer may become
* inaccessible at any time, for example if the mapped file is truncated. An
* attempt to access an inaccessible region of a mapped byte buffer will not
* change the buffer's content and will cause an unspecified exception to be
* thrown either at the time of the access or at some later time. It is
* therefore strongly recommended that appropriate precautions be taken to
* avoid the manipulation of a mapped file by this program, or by a
* concurrently running program, except to read or write the file's content.
*
* <p> Mapped byte buffers otherwise behave no differently than ordinary direct
* byte buffers. </p>
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
public abstract class
MappedByteBuffer
extends
ByteBuffer
{
// This is a little bit backwards: By rights MappedByteBuffer should be a
// subclass of DirectByteBuffer, but to keep the spec clear and simple, and
// for optimization purposes, it's easier to do it the other way around.
// This works because DirectByteBuffer is a package-private class.
// For mapped buffers, a FileDescriptor that may be used for mapping
// operations if valid; null if the buffer is not mapped.
private final
FileDescriptor fd;
// This should only be invoked by the DirectByteBuffer constructors
//
MappedByteBuffer(int
mark, int
pos, int
lim, int
cap, // package-private
FileDescriptor fd)
{
super(
mark,
pos,
lim,
cap);
this.
fd =
fd;
}
MappedByteBuffer(int
mark, int
pos, int
lim, int
cap) { // package-private
super(
mark,
pos,
lim,
cap);
this.
fd = null;
}
private void
checkMapped() {
if (
fd == null)
// Can only happen if a luser explicitly casts a direct byte buffer
throw new
UnsupportedOperationException();
}
// Returns the distance (in bytes) of the buffer from the page aligned address
// of the mapping. Computed each time to avoid storing in every direct buffer.
private long
mappingOffset() {
int
ps =
Bits.
pageSize();
long
offset =
address %
ps;
return (
offset >= 0) ?
offset : (
ps +
offset);
}
private long
mappingAddress(long
mappingOffset) {
return
address -
mappingOffset;
}
private long
mappingLength(long
mappingOffset) {
return (long)
capacity() +
mappingOffset;
}
/**
* Tells whether or not this buffer's content is resident in physical
* memory.
*
* <p> A return value of <tt>true</tt> implies that it is highly likely
* that all of the data in this buffer is resident in physical memory and
* may therefore be accessed without incurring any virtual-memory page
* faults or I/O operations. A return value of <tt>false</tt> does not
* necessarily imply that the buffer's content is not resident in physical
* memory.
*
* <p> The returned value is a hint, rather than a guarantee, because the
* underlying operating system may have paged out some of the buffer's data
* by the time that an invocation of this method returns. </p>
*
* @return <tt>true</tt> if it is likely that this buffer's content
* is resident in physical memory
*/
public final boolean
isLoaded() {
checkMapped();
if ((
address == 0) || (
capacity() == 0))
return true;
long
offset =
mappingOffset();
long
length =
mappingLength(
offset);
return
isLoaded0(
mappingAddress(
offset),
length,
Bits.
pageCount(
length));
}
// not used, but a potential target for a store, see load() for details.
private static byte
unused;
/**
* Loads this buffer's content into physical memory.
*
* <p> This method makes a best effort to ensure that, when it returns,
* this buffer's content is resident in physical memory. Invoking this
* method may cause some number of page faults and I/O operations to
* occur. </p>
*
* @return This buffer
*/
public final
MappedByteBuffer load() {
checkMapped();
if ((
address == 0) || (
capacity() == 0))
return this;
long
offset =
mappingOffset();
long
length =
mappingLength(
offset);
load0(
mappingAddress(
offset),
length);
// Read a byte from each page to bring it into memory. A checksum
// is computed as we go along to prevent the compiler from otherwise
// considering the loop as dead code.
Unsafe unsafe =
Unsafe.
getUnsafe();
int
ps =
Bits.
pageSize();
int
count =
Bits.
pageCount(
length);
long
a =
mappingAddress(
offset);
byte
x = 0;
for (int
i=0;
i<
count;
i++) {
x ^=
unsafe.
getByte(
a);
a +=
ps;
}
if (
unused != 0)
unused =
x;
return this;
}
/**
* Forces any changes made to this buffer's content to be written to the
* storage device containing the mapped file.
*
* <p> If the file mapped into this buffer resides on a local storage
* device then when this method returns it is guaranteed that all changes
* made to the buffer since it was created, or since this method was last
* invoked, will have been written to that device.
*
* <p> If the file does not reside on a local device then no such guarantee
* is made.
*
* <p> If this buffer was not mapped in read/write mode ({@link
* java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this
* method has no effect. </p>
*
* @return This buffer
*/
public final
MappedByteBuffer force() {
checkMapped();
if ((
address != 0) && (
capacity() != 0)) {
long
offset =
mappingOffset();
force0(
fd,
mappingAddress(
offset),
mappingLength(
offset));
}
return this;
}
private native boolean
isLoaded0(long
address, long
length, int
pageCount);
private native void
load0(long
address, long
length);
private native void
force0(
FileDescriptor fd, long
address, long
length);
}