使用(GatheringByteChannel)RandomAccessFile.getChannel.write(缓冲区)丢失数据

时间:2015-12-08 09:52:56

标签: nio randomaccessfile filechannel data-loss

我打开raf,获取文件通道,然后在缓冲区中累积一些数据

channel.position(raf.length)
channel.write(buffers)
channel.close
raf.close

我希望在这些偏移处将字节写入raf,这是raf.length +数组中累积的缓冲区大小

0,62,132,195,259,322,392,455,519,589,652,716,779,842,905,968,1031,1093,1155,1225,1287,1350,1414,1477,1541,1611,1674,1737,1801,1863,1927,1989,2059,2123,2193,2256,2319,2382,2452,2516,2586,2648,2711,2774,2837,2900,2962,3025,3089,3152,3216,3286,3348,3412,3482,3544,3614,3684,3754,3818,3882,3952,4022,4092

和ProcMon显示这是OS级别开始发生的事情

"CreateFile","objects.bin","SUCCESS","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened"
"QueryNetworkOpenInformationFile","objects.bin","SUCCESS","CreationTime: 6.12.2015 20:11:21, LastAccessTime: 8.12.2015 11:03:49, LastWriteTime: 8.12.2015 11:03:49, ChangeTime: 8.12.2015 11:03:49, AllocationSize: 1.01.1601 2:00:00, EndOfFile: 1.01.1601 2:00:00, FileAttributes: ANCI"
"CloseFile","objects.bin","SUCCESS",""
"CreateFile","objects.bin","SUCCESS","Desired Access: Read Attributes, Delete, Disposition: Open, Options: Non-Directory File, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened"
"QueryAttributeTagFile","objects.bin","SUCCESS","Attributes: ANCI, ReparseTag: 0x0"
"SetDispositionInformationFile","objects.bin","SUCCESS","Delete: True"
"CloseFile","objects.bin","SUCCESS",""
"CreateFile","objects.bin","SUCCESS","Desired Access: Generic Read/Write, Disposition: OpenIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Created"
"QueryStandardInformationFile","objects.bin","SUCCESS","AllocationSize: 0, EndOfFile: 0, NumberOfLinks: 1, DeletePending: False, Directory: False"
"WriteFile","objects.bin","SUCCESS","Offset: 0, Length: 62, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 62, Length: 70, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 132, Length: 63, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 195, Length: 64, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 259, Length: 63, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 322, Length: 70, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 392, Length: 63, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 455, Length: 64, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 519, Length: 70, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 589, Length: 63, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 652, Length: 64, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 716, Length: 63, Priority: Normal"
"WriteFile","objects.bin","SUCCESS","Offset: 779, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 842, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 905, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 968, Length: 63"
"ReadFile","objects.bin","END OF FILE","Offset: 2 452, Length: 2"
"QueryStandardInformationFile","objects.bin","SUCCESS","AllocationSize: 4 096, EndOfFile: 1 031, NumberOfLinks: 1, DeletePending: False, Directory: False"
"WriteFile","objects.bin","SUCCESS","Offset: 1 031, Length: 64"
"WriteFile","objects.bin","SUCCESS","Offset: 1 095, Length: 70"
"WriteFile","objects.bin","SUCCESS","Offset: 1 165, Length: 70"
"WriteFile","objects.bin","SUCCESS","Offset: 1 235, Length: 64"
"WriteFile","objects.bin","SUCCESS","Offset: 1 299, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 362, Length: 64"
"WriteFile","objects.bin","SUCCESS","Offset: 1 426, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 489, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 552, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 615, Length: 64"
"WriteFile","objects.bin","SUCCESS","Offset: 1 679, Length: 70"
"WriteFile","objects.bin","SUCCESS","Offset: 1 749, Length: 64"
"WriteFile","objects.bin","SUCCESS","Offset: 1 813, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 876, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 1 939, Length: 63"
"WriteFile","objects.bin","SUCCESS","Offset: 2 002, Length: 63"
"CloseFile","objects.bin","SUCCESS",""

如您所见,它在偏移量0,62,132,......最多968处写入16个缓冲区并关闭文件!接下来它再次打开它并继续进行偏移1031,1095,1165,它来自另一个会话,我也这样做:打开raf和fc,然后编写另一系列缓冲区,在再次写入16个缓冲区后中断。第二个系列从1031开始,其中文件被关闭,并且它是第一次写入时第17个缓冲区的位置。我see nothing在jdocs中约有16个缓冲区限制。

幸运的是,fileChannel.force无法解决这种情况,因为除非系统关闭,否则我不需要在磁盘上物理数据。我很高兴在fc.write时间或当JVM关闭时刷新到OS缓存中的数据,以便下次在同一系统中打开文件时它可用。

这是the program to reproduce the bug

object FileChannelFailureDemo extends App {

  import java.nio._, java.io._, java.nio.channels._

  val raf = new RandomAccessFile("""objects2""", "rw") ; val fc = raf.getChannel
  val range = (1 to 20)
  val ba = range.map (i => ByteBuffer.wrap(Array.ofDim[Byte](i)))
  fc.write(ba.toArray)                      //> res0: Long = 136

  val expectedLength = range.foldLeft(0){case (acc, i) => acc + i}
                                                  //> expectedLength  : Int = 210
  // 1+2+..+20 = 20*21/2 = 210 // epxected len
  // 1+2+..+16 = 16*17/2 = 136 // len of file if only 16 buffers written
  // assertion here, file size 136 != 210                                                 
  assert(raf.length == expectedLength , raf.length + " != " + expectedLength)
                                                  //> java.lang.AssertionError: assertion failed: 136 != 210
                                                  //|   at scala.Predef$.assert(Predef.scala:165)
  println("succeeded, file size is " + raf.length)
  fc.close; raf.close
}

奇怪的是,它并没有在那台远程机器上复制。如果从控制台运行这个简短的程序,我也看不到它,但这段代码无法从Worksheet执行断言。它似乎取决于程序状态。它可能会失败或成功使用相同的JRE。

0 个答案:

没有答案