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

Memory-Mapped files cannot be renamed

    XMLWordPrintable

Details

    • Enhancement
    • Resolution: Won't Fix
    • P3
    • None
    • 7u9
    • core-libs

    Description

      FULL PRODUCT VERSION :
      java version " 1.7.0_09 "
      Java (TM) SE Runtime Environment (build 1.7.0_09-b05)
      Java HotSpot (TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.1.7601]

      A DESCRIPTION OF THE PROBLEM :
      MappedByteBuffer does not provide a unmap method to unmap a memory-mapped file. Our application uses memory-mapped IO to read data from memory-mapped archive files. If new data is added to one of the archive files, the old file is deleted and a new file is created. On Windows it is not possible to delete memory-mapped files. As a workaround we renamed mapped files we want to delete and deleted them after the GC has unmapped the file.

      With Java Plattform Standard Edition 6.0 it was possible to rename memory-mapped files on Windows using File.renameTo(File dst). Unfortunately that is no longer possible with Java 7.

      With Java 7 our only option now seems to be to use

      sun.misc.Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
      cleaner.clean();

      and then delete the file. Please either make it possible to rename memory-mapped files on Windows again or preferably add a unmap method to MappedByteBuffer.



      REGRESSION. Last worked in version 6u31

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Open a file, get the filechannel, then create a mapped byte buffer. Try to rename the file using file.renameTo(dst) or Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING).

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      file.renameTo(dst) or Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING) should rename memory-mapped files on Windows.
      ACTUAL -
      Memory-Mapped files cannot be renamed on Windows. Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING) will throw an exception:

      java.nio.file.FileSystemException: c:\Temp\test.bin -> c:\Temp\test2.bin: The process cannot access the file because it is being used by another process.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.nio.file.FileSystemException: c:\Temp\test.bin -> c:\Temp\test2.bin: The process cannot access the file because it is being used by another process.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package mappedbytebuffertest;

      import sun.nio.ch.DirectBuffer;

      import java.io.*;
      import java.nio.MappedByteBuffer;
      import java.nio.channels.FileChannel;
      import java.nio.file.Files;
      import java.nio.file.Path;
      import java.nio.file.StandardCopyOption;

      public class Main {

          public static void main(String[] args) throws Exception {
              File file = new File( " c:\\Temp\\test.bin " );
              // create file and add some data to it if it does not already exist
              if (!file.exists()) {
                  FileOutputStream fout = new FileOutputStream(file);
                  DataOutputStream dout = new DataOutputStream(fout);
                  for(int i = 0; i < 1024; i++) dout.write(i);
                  dout.close();
                  fout.close();
              }

              // now map the file
              FileInputStream is = new FileInputStream(file);
              MappedByteBuffer buffer = is.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, is.getChannel().size());
              is.close();

              // now try to rename the file
              File dst = new File( " c:\\Temp\\test2.bin " );
              if (file.renameTo(dst)) System.out.println( " Renamed file to " + dst); else System.out.println( " Could not rename file to " + dst);

              // try the new JDK 7 API
              Path path = file.toPath();
              Path dstPath = dst.toPath();
              try {
                  Files.move(path, dstPath, StandardCopyOption.REPLACE_EXISTING);
                  System.out.println( " Renamed file to " + dstPath);
              } catch (IOException ex) {
                  System.out.println( " Could not rename file to " + dstPath + " reason: " + ex);
              }

              // now unmap the file
              sun.misc.Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
              cleaner.clean();

              // try the new JDK 7 API
              try {
                  Files.move(path, dstPath, StandardCopyOption.REPLACE_EXISTING);
                  System.out.println( " Renamed file to " + dstPath);
              } catch (IOException ex) {
                  System.out.println( " Could not rename file to " + dstPath + " reason: " + ex);
              }
          }
      }

      Running this programm will produce the following output:

      Could not rename file to c:\Temp\test2.bin
      Could not rename file to c:\Temp\test2.bin reason: java.nio.file.FileSystemException: c:\Temp\test.bin -> c:\Temp\test2.bin: The process cannot access the file because it is being used by another process.

      Renamed file to c:\Temp\test2.bin
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Unmap the file before renaming it, using:

      sun.misc.Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
      cleaner.clean();

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              coffeys Sean Coffey
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: