Uploaded image for project: 'Harmony'
  1. Harmony
  2. HARMONY-4081

[classlib][nio] FileChannel.write(ByteBuffer[]) sometimes works incorrectly

    XMLWordPrintableJSON

Details

    • Bug
    • Status: In Progress
    • Minor
    • Resolution: Unresolved
    • None
    • None
    • Classlib
    • None
    • Windows
    • Patch Available

    Description

      According to J2SE specification
      "File channels are safe for use by multiple concurrent threads."

      But the following test demonstrates that FileChannel.write(ByteBuffer[]) sometimes works incorrectly when
      some threads try to write bytes to the same channel.

      Not all data are written to the file.
      --------------fchTest.java--------------
      import java.io.File;
      import java.io.IOException;
      import java.io.FileOutputStream;
      import java.io.FileInputStream;
      import java.nio.channels.FileChannel;
      import java.nio.ByteBuffer;

      public class fchTest {

      public static int N_TH = 20;
      public static final int BUF_SIZE = 2000;
      public static final int N_BUF = 20;
      public static final int N_WRITES = 20;

      boolean passed = true;

      String fileName = "FileChannel.file";
      FileChannel outChannel = null;
      FileChannel inChannel = null;

      public static void main(String[] args) {
      try {
      if (args.length > 0)

      { N_TH = Integer.parseInt(args[0]); }

      } catch (Throwable e) {
      }
      int res = new fchTest().test(args);
      System.err.println(res == 104 ? "Test passed" : "Test failed");
      }
      public int test(String[] params) {
      File f = null;
      passed = true;
      try {
      f = new File(fileName);
      if (f.exists())

      { f.delete(); }
      outChannel = new FileOutputStream(f).getChannel();
      inChannel = new FileInputStream(f).getChannel();

      Thread[] t = new Thread[N_TH];
      for (int i = 0; i < t.length; ++i) { t[i] = new thWriter(this); t[i].start(); }

      for (int i = 0; i < t.length; ++i) { t[i].join(); }
      } catch (Throwable t) { t.printStackTrace(); return 105; } finally {
      try {
      if (outChannel != null){ outChannel.close(); }
      if (inChannel != null){ inChannel.close(); }
      } catch (Throwable t){ t.printStackTrace(); }
      if (f != null){ f.delete(); }

      }
      return (passed ? 104 : 106);
      }

      }
      class thWriter extends Thread {
      FileChannel outChannel = null;
      fchTest base = null;

      thWriter(fchTest base)

      { this.outChannel = base.outChannel; this.base = base; }

      public void run () {
      try {
      long allW = 0;
      long allC = 0;
      for (int i = 0; i < fchTest.N_WRITES; ++i) {
      ByteBuffer[] bbb = createByteChunks();
      for (int t = 0; t < bbb.length; t++)

      { allC += bbb[i].capacity(); }

      long written = outChannel.write(bbb);
      if (written != (long)((fchTest.BUF_SIZE)*fchTest.N_BUF))

      { System.err.println(this+" Written: "+written+" should be "+ fchTest.BUF_SIZE*fchTest.N_BUF+" outChannel position: "+outChannel.position()); base.passed = false; }

      allW+=written;
      Thread.yield();
      Thread.sleep(10);
      }
      System.err.println(this+" - after write: "allW" "+allC);
      if (allW != allC)

      { base.passed = false; }

      outChannel.force(false);

      } catch (Throwable e)

      { System.err.println(this+" unexpected exception " + e); e.printStackTrace(); base.passed = false; }

      }

      ByteBuffer[] createByteChunks() {
      ByteBuffer[] bb_arr = new ByteBuffer[fchTest.N_BUF];
      byte [] bb = new byte[fchTest.BUF_SIZE];
      for (int i = 0; i < bb.length; i++)

      { bb[i] = (byte)i; }

      for (int i = 0; i < bb_arr.length; ++i)

      { bb_arr[i] = ByteBuffer.allocateDirect(bb.length).wrap(bb); }


      return bb_arr;
      }
      }
      ----------------------------------------------------
      Run this test several times and change the number of created threads
      java fchTest
      java fchTest 30

      Output on RI:
      ==============
      java version "1.5.0_06"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
      Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)

      Thread[Thread-1,5,main] - after write: 800000 800000
      Thread[Thread-11,5,main] - after write: 800000 800000
      Thread[Thread-19,5,main] - after write: 800000 800000
      Thread[Thread-17,5,main] - after write: 800000 800000
      Thread[Thread-9,5,main] - after write: 800000 800000
      Thread[Thread-13,5,main] - after write: 800000 800000
      Thread[Thread-15,5,main] - after write: 800000 800000
      Thread[Thread-7,5,main] - after write: 800000 800000
      Thread[Thread-3,5,main] - after write: 800000 800000
      Thread[Thread-0,5,main] - after write: 800000 800000
      Thread[Thread-5,5,main] - after write: 800000 800000
      Thread[Thread-16,5,main] - after write: 800000 800000
      Thread[Thread-6,5,main] - after write: 800000 800000
      Thread[Thread-12,5,main] - after write: 800000 800000
      Thread[Thread-2,5,main] - after write: 800000 800000
      Thread[Thread-8,5,main] - after write: 800000 800000
      Thread[Thread-10,5,main] - after write: 800000 800000
      Thread[Thread-4,5,main] - after write: 800000 800000
      Thread[Thread-14,5,main] - after write: 800000 800000
      Thread[Thread-18,5,main] - after write: 800000 800000
      Test passed

      Output on DRLVM:
      ==============
      Apache Harmony Launcher : (c) Copyright 1991, 2006 The Apache Software Foundation or its licensors, as applicable.
      java version "1.5.0"
      pre-alpha : not complete or compatible
      svn = r544707, (Jun 6 2007), Windows/ia32/msvc 1310, release build
      http://harmony.apache.org
      The GC did not provide gc_add_weak_root_set_entry()
      Thread[Thread-9,5,main] Written: 33100 should be 40000 outChannel position: 6874000
      Thread[Thread-20,5,main] - after write: 800000 800000
      Thread[Thread-16,5,main] - after write: 800000 800000
      Thread[Thread-8,5,main] - after write: 800000 800000
      Thread[Thread-12,5,main] - after write: 800000 800000
      Thread[Thread-22,5,main] - after write: 800000 800000
      Thread[Thread-14,5,main] - after write: 800000 800000
      Thread[Thread-18,5,main] - after write: 800000 800000
      Thread[Thread-23,5,main] - after write: 800000 800000
      Thread[Thread-11,5,main] - after write: 800000 800000
      Thread[Thread-10,5,main] - after write: 800000 800000
      Thread[Thread-24,5,main] - after write: 800000 800000
      Thread[Thread-7,5,main] - after write: 800000 800000
      Thread[Thread-15,5,main] - after write: 800000 800000
      Thread[Thread-9,5,main] - after write: 793100 800000
      Thread[Thread-6,5,main] - after write: 800000 800000
      Thread[Thread-25,5,main] - after write: 800000 800000
      Thread[Thread-17,5,main] - after write: 800000 800000
      Thread[Thread-13,5,main] Written: 37700 should be 40000 outChannel position: 15872000
      Thread[Thread-19,5,main] - after write: 800000 800000
      Thread[Thread-13,5,main] - after write: 797700 800000
      Thread[Thread-21,5,main] - after write: 800000 800000
      Test failed

      This bug causes the failure of the test
      api.nio.channels.filechannel.FileChannelThrSafetyTest
      from Reliability test suite https://issues.apache.org/jira/browse/HARMONY-2918

      Attachments

        1. H-4081_fix.patch
          3 kB
          Mikhail Markov
        2. H-4081_temp_workaround.patch
          1 kB
          Mikhail Markov
        3. SourceViewScreenshot-1.jpg
          233 kB
          Ilya Leviev

        Issue Links

          Activity

            People

              Unassigned Unassigned
              vpetrash Vera Petrashkova
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated: