Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6539707

(fc) MappedByteBuffer.force() method throws an IOException in a very simple test

    Details

    • Type: Bug
    • Status: Open
    • Priority: P4
    • Resolution: Unresolved
    • Affects Version/s: 7
    • Fix Version/s: tbd
    • Component/s: core-libs
    • Labels:
    • Subcomponent:
    • Understanding:
      Cause Known
    • Introduced In Version:
    • CPU:
      x86
    • OS:
      windows_xp

      Description

      FULL PRODUCT VERSION :
      java version "1.7.0-ea"
      Java(TM) SE Runtime Environment (build 1.7.0-ea-b10)
      Java HotSpot(TM) Client VM (build 1.7.0-ea-b10, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      1.25 GB RAM, ~7 GB free disk space

      A DESCRIPTION OF THE PROBLEM :
      If I create a new large file, map some block before the file end, write something to the MappedByteBuffer and then try to call its "force()" method, it throws IOException with a message "The process cannot access the file because another process has locked a portion of the file". Please see the attached source code.

      I think this bug is connected with recently fixed bug #4938372. Unfortunately, though that bug was corrected in Java 1.7.0-b10, this one still exists.

      This bug occurs under both JDK 1.6.0 and 1.7.0 (the latest release b10).

      Comment, please, what is estimated time of fixing this.

      The test published there leads to java.io.IOException in MappedByteBuffer.force(). I understand, it's possible that bug will not be resolved in nearest time. However, in any case, this method does not declare any exceptions and, according its contract, cannot throw checked exceptions at all!

      I think, while the bug #6539707 is not fixed, it's necessary to perform two little corrections.

      1) In a case of the discussed problem, force() method must throw java.io.IOError instead IOException.

      2) An ability of throwing IOError should be documented in the comments to force() method. For example: "In some situations, this method may throw IOError and not perform actual flushing data to the storage device. In this case, you may try to repeat calling this method again after some little time: probably it will not fail."

      Then, at least, the programmers will be able to implement own schemes of avoiding that bug. Usually, the failure of force() method is not a catastrophe: the data will still be written on disk after a little time, and almost all possible program invariants will not be violated. The IOError, that will be thrown by this method, in many situations can be catched and then be ignored (maybe with logging) or lead to scheduling force() to some future moment.

      Unlike this, now IOException is thrown unexpectedly for a programmer (no any API specification about this probability). Moreover, we cannot easily catch this exception: the compiler does not allow using "try {mbb.force();} catch (IOException e) {...}" operators, because IOException is not declared in "throws" statement.

      Maybe, it makes sense to offer a special exception "ForceError" (extends IOError) to distinguish the discussed little defect of Windows FlushViewOfFile function from the really serious disk crash.



      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1) Please make sure that the current directory does not contain "test.dat" file (or remove it if you called my test before this). The bug always occurs on my computer with NEW files, but sometimes all works fine when the file already exists. Please also make sure that there is enough free disk space (the size of created file is 400 MB).

      2) Compile the attached test:
      "\Program Files\Java\jdk1.7.0\bin\javac" Test.java

      3) Run it:
      "\Program Files\Java\jdk1.7.0\jre\bin\java" Test


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Normal execution without exceptions.
      ACTUAL -
      IOException while calling force() method.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "main" java.io.IOException: The process cannot access the file because another process has locked a portion of the file
      at java.nio.MappedByteBuffer.force0(Native Method)
      at java.nio.MappedByteBuffer.force(MappedByteBuffer.java:144)
      at Test.main(Test.java:18)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.*;
      import java.nio.*;
      import java.nio.channels.*;
      public class Test {
          public static void main(String[] args) throws IOException {
              int blockSize = 2048 * 1024;
              int numberOfBlocks = 200;
              int fileLength = numberOfBlocks * blockSize;
              RandomAccessFile raf = new RandomAccessFile("test.dat", "rw");
              raf.setLength(fileLength);
              int pos = (numberOfBlocks - 1) * blockSize;
              int size = (int)Math.min(blockSize, fileLength - pos);
              MappedByteBuffer mbb = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, pos, size);
              System.out.println("Write region 0x" + Long.toHexString(pos) + "..+0x" + Long.toHexString(size));
              for (int k = 0; k < mbb.limit(); k++)
                  mbb.put(k, (byte)65);
              System.out.println("Force");
              mbb.force();
              System.out.println("OK");
              raf.close();
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      I know only the simplest safe solution: never use force() method while mapping any portion of a file. Unfortunately, it leads to catastrophic results due to swapping problems, if we need to consecutively map and write a file larger than the amount of RAM.

      For example, on my computer (1.25 GB RAM, ~2 GB Windows virtual memory), I tried to create a file with the length 1.5-4.0 GB and fill it by some value in a simple mapping loop:
      for (long p = 0; p < fileLength; p += blockSize) {
          MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, p, blockSize);
          for (int k = 0; k < mbb.limit(); k++)
               mbb.put(k, (byte)65);
          mbb.force();
      }
      Without force() call, this test quickly leads to catastrophic swapping of all other programs and OS kernel. The computer becomes "dead" and almost does not react to keyboard and mouse.

        Attachments

          Activity

            People

            • Assignee:
              bpb Brian Burkhalter
              Reporter:
              ndcosta Nelson Dcosta (Inactive)
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Imported:
                Indexed: