JDK-4833719 : (bf) Views of MappedByteBuffers are not MappedByteBuffers, and cannot be forced
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2003-03-17
  • Updated: 2021-04-01
  • Resolved: 2021-03-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17
17 b16Fixed
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Description

Name: nt126004			Date: 03/17/2003


FULL PRODUCT VERSION :
J2SE 1.4.1 and higher

FULL OS VERSION :
Common issue for all OSes....

A DESCRIPTION OF THE PROBLEM :
The .force() call on a MappedByteBuffer object fails if the buffer was cast to a MappedByteBuffer from a DirectByteBuffer object which was created with MappedByteBuffer.duplicate() or MappedByteBuffer.slice().  The problem is a call to checkMapped() method inside the MappedbyteBuffer class.

I can change the isAMappedBuffer value in debug and force the program to do its thing properly, but there is not a way to do this within a running program.  It seems like the MappedByteBuffer class should NOT throw an exception unless it is ACTUALLY not backed by a MappedByteBuffer.

In other words, when the .duplicate() or .slice() is called, it should carry over the isAMappedBuffer from the original MappedByteBuffer object.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a MappedByteBuffer using channel.map()
2. MappedByteBuffer buf2 = buf.duplicate();
3. MappedByteBuffer buf3 = (MappedByteBuffer) buf2;
4. buf3.force();

.force() call on DirectByteBuffer object cast to MappedByteBuffer fail if they were created with .duplicate() or .slice() from a MappedByteBuffer.  The problem is a call to checkMapped() method inside the MappedbyteBuffer class.  I can change the isAMappedBuffer value in debug and force the program to do its thing properly, but there is not a way to do this within a running program.  It seems like the MappedByteBuffer class should NOT throw an exception unless it is ACTUALLY not backed by a MappedByteBuffer.  In other words, when the .duplicate() or .slice() is called, it should carry over the isAMappedBuffer from the original MappedByteBuffer object.

EXPECTED VERSUS ACTUAL BEHAVIOR :
It seems like the MappedByteBuffer class should NOT throw an exception unless it is ACTUALLY NOT backed by a MappedByteBuffer.

In other words, when the .duplicate() or .slice() is called, it should carry over the isAMappedBuffer from the original MappedByteBuffer object.  This way the exception would not be thrown incorrectly and would allow the force0 to be called.
isAMappedBuffer is set to false when the .duplicate() or slice() completes.  This causes no update to MMF and Exception: UnsupportedOperationException when the .force() is called on the new duplicated or sliced buffer.  You must cast the buffer back to a MappedByteBuffer in order to get access to .force().

ERROR MESSAGES/STACK TRACES THAT OCCUR :
testMMF main() startup
Exception in thread "main" java.lang.UnsupportedOperationException
        at java.nio.MappedByteBuffer.checkMapped(MappedByteBuffer.java:76)
        at java.nio.MappedByteBuffer.force(MappedByteBuffer.java:137)
        at CROSS.System.os.MMFDataBlock.flushToDisk(MMFDataBlock.java:147)
        at CROSS.System.os.MMFBufferedOutputStream.flushToDisk(MMFBufferedOutput
Stream.java:200)
        at testMMF.main(testMMF.java:129)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package CROSS.ReproductBugs;

import java.io.RandomAccessFile;
import java.nio.*;
import java.nio.channels.*;

class ReproductBugs {
    ReproductBugs() {
        RandomAccessFile fileRW;
        FileChannel fcRW;
        MappedByteBuffer buf2;

        try {
            fileRW = new RandomAccessFile("test.fil", "rwd");
        } catch (java.io.FileNotFoundException e) {
            e.printStackTrace();
            return;
        }

        fcRW = fileRW.getChannel();
        try {
            if (fileRW.length() < 10000) {
                fileRW.setLength(10000);
            }
        } catch (java.io.IOException e) {
            e.printStackTrace();
            return;
        }

        MappedByteBuffer mapbufRW;
        try {
            mapbufRW = fcRW.map(java.nio.channels.FileChannel.MapMode.READ_WRITE, 0, 10000);
        } catch (java.io.IOException e) {
            e.printStackTrace();
            return;
        }

        buf2 = (MappedByteBuffer) mapbufRW.duplicate();
        buf2.put("This is a test".getBytes());
        buf2.force();

    }

    public static void main(String[] args) {
        ReproductBugs rb = new ReproductBugs();
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I don't know of any solution outside of forcing the underlying MappedByteBuffer.  This would require me to track that relationship with a hashmap or something on that order.  This is not acceptable in some cases, in others we might be able to work with it.  I can't seem to find much of anything on this topic in the the forums, etc.
(Review ID: 182700) 
======================================================================

Comments
Changeset: b006f22f Author: Brian Burkhalter <bpb@openjdk.org> Date: 2021-03-25 15:30:50 +0000 URL: https://git.openjdk.java.net/jdk/commit/b006f22f
25-03-2021

EVALUATION At present the duplicate and slice methods defined in the ByteBuffer class are specified to return ByteBuffers, not MappedByteBuffers or DirectByteBuffers, the latter of which are an internal implementation class. The described behavior is intended and is not a bug. Having said that, with the introduction of generics in 1.5 it might be possible to enhance the ByteBuffer class by adding type parameters to the return types of the duplicate, slice, and similar view-buffer methods so that a view of a MappedByteBuffer is itself a MappedByteBuffer. I'm therefore turning this into an RFE for consideration in 1.5. -- ###@###.### 2003/3/18
03-11-0184

WORK AROUND Maintain a WeakHashMap that maps the views of a MappedByteBuffer to the MappedByteBuffer itself. When you need to force an update but you only have a reference to a view, look up the MappedByteBuffer in the WeakHashMap and force the MappedByteBuffer. -- ###@###.### 2003/3/18
03-11-0184