[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-nio-dev
Subject:    Re: (fc) FileChannel.transferFrom/transferFromArbitraryChannel to return -1 at some error condition
From:       Hamlin <lihuaming3 () huawei ! com>
Date:       2021-01-30 0:56:58
Message-ID: 5de3436d-7ec7-1100-674f-31ac000dcb01 () huawei ! com
[Download RAW message or body]

(send out the same message in thunderbird)


在 2021/1/28 16:19, Alan Bateman 写道:
> On 28/01/2021 00:49, lihuaming (A) wrote:
> > 
> > Hi Everyone,
> > 
> > in FileChannel.transferFromArbitraryChannel, when src.read returns 
> > -1, it means "the channel has reached end-of-stream", it could be a 
> > socket underlying is reset by peer host, or some other conditions. 
> > But this "-1" is completely hidden when transferFromArbitraryChannel 
> > returns back to File.Channel.transferFrom.
> > 
> > Would it better to return -1 in 
> > FileChannel.transferFrom/transferFromArbitraryChannel when src.read 
> > returns -1 and tw is 0?
> > 
> > 
> Hi Hamlin,
> 
> The transferFrom method returns the number of bytes written to the 
> file. Changing the spec to allow it return -1 would be an incompatible 
> change and could potentially break usages that keep a running total of 
> bytes transferred.

Hi Alan,

Yes, I think so too. But still like to see if we can improve it a little 
bit.

> 
> Can you expand a bit on the scenario? If the underlying connection has 
> been reset or there is another error then I would expect the read from 
> the source channel to fail (SocketException "connection reset" for 
> example). This is different to the peer closing the connection 
> gracefully where reading from the source channel returns -1/EOF and 
> there are no bytes written to the file.

Here is a simple demo, I don't use FileChannel.transferFrom directly, 
but I hope I can clarify the situation.

When ServerHangHttp and Client are up for a while (please check the 
bottom), no matter Server close the socket explicitly or kill by "kill 
-9 xxx", the client side will print out "[client] read : -1" 
continuously. so, if we are using FileChannel.transferFrom which will 
call transferFromArbitraryChannel which will call 
ReadableByteChannel.read, ReadableByteChannel.read will return -1, but 
transferFromArbitraryChannel will return 0, so as 
FileChannel.transferFrom. Based on this return value, following while 
loop will be a infinite loop, and user don't want to call something like 
"call sth like srcSocketChannel.read(...)", please check the reason in 
comments below.

while (srcSocketChannel.isOpen()) {
   long l = fileChannel.transferFrom(srcSocketChannel,...);
   // user could call sth like srcSocketChannel.read(...), and expect it return -1, \
and break the loop, but it will be unacceptable for some program, where they would \
like to very quick copy, so called "zero" copy through fileChannel.transferFrom, and \
they don't want to add an extra check like "srcSocketChannel.read(...)"  if (l == -1) \
{ // break out the while loop } }

At this situation, I think it's more friendly to have 
fileChannel.transferFrom returns -1.

Thanks,

Hamlin

=========== ServerHangHttp and Client ==============

public class ServerHangHttp {
         public static void main(String args[]) throws Exception {
                 ServerSocketChannel server = ServerSocketChannel.open();
                 server.bind(new InetSocketAddress("127.0.0.1", 9876));
                 System.out.println("            waiting for client...");
                 SocketChannel client = server.accept();
                 System.out.println("            get client connection 
successfully");
                 System.out.println("            socket: " + client);
                 int i = 0;
                 while (client.isOpen()) {
                         System.out.println("            write some 
bytes to client");
client.write(ByteBuffer.wrap("abc".getBytes()));
                         Thread.sleep(1000);
                         /*
                          * if (++i == 10) {
                                 System.out.println(" socket is closed");
                                 client.close();
                                 break;
                         }*/
                 }

         }
}

public class Client {
         public static void main(String args[]) throws Exception {
                 SocketChannel client = SocketChannel.open(new 
InetSocketAddress("127.0.0.1", 9876));
                 System.out.println("[client] socket: " + client);
                 int i = 0;
                 ByteBuffer buf = ByteBuffer.allocate(1000);
                 while (true) {
                         int x = client.read(buf);
                         System.out.println("[client] read : " + x);
                         Thread.sleep(1000);
                 }
         }
}


> 
> -Alan.
> 


[Attachment #3 (text/html)]

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    (send out the same message in thunderbird)
    <p><br>
    </p>
    <div class="moz-cite-prefix">在 2021/1/28 16:19, Alan Bateman 写道:<br>
    </div>
    <blockquote type="cite"
      cite="mid:f0d14384-b663-7398-439d-fd2657470617@oracle.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      On 28/01/2021 00:49, lihuaming (A) wrote:<br>
      <blockquote type="cite"
cite="mid:FF52E71F75D5A341BDD9AB1622091FA5012103D3@DGGEML523-MBX.china.huawei.com">
        <meta name="Generator" content="Microsoft Word 15 (filtered
          medium)">
        <style>@font-face
	{font-family:\5B8B\4F53;
	panose-1:2 1 6 0 3 1 1 1 1 1;}@font-face
	{font-family:"Cambria Math";
	panose-1:2 4 5 3 5 4 6 3 2 4;}@font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}@font-face
	{font-family:"\@\5B8B\4F53";
	panose-1:2 1 6 0 3 1 1 1 1 1;}p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Calibri",sans-serif;}a:link, span.MsoHyperlink
	{mso-style-priority:99;
	color:#0563C1;
	text-decoration:underline;}a:visited, span.MsoHyperlinkFollowed
	{mso-style-priority:99;
	color:#954F72;
	text-decoration:underline;}span.EmailStyle17
	{mso-style-type:personal-compose;
	font-family:"Calibri",sans-serif;
	color:windowtext;}.MsoChpDefault
	{mso-style-type:export-only;
	font-family:"Calibri",sans-serif;}div.WordSection1
	{page:WordSection1;}</style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
        <div class="WordSection1">
          <p class="MsoNormal"><span lang="EN-US">Hi Everyone,<o:p></o:p></span></p>
          <p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
          <p class="MsoNormal"><span
style="font-family:&quot;Arial&quot;,sans-serif;color:#172B4D;background:white"
              lang="EN-US">in FileChannel.transferFromArbitraryChannel,
              when src.read returns -1, it means "the channel has
              reached end-of-stream", it could be a socket underlying is
              reset by peer host, or some other conditions. But this
              "-1" is completely hidden when
              transferFromArbitraryChannel returns back to
              File.Channel.transferFrom.<o:p></o:p></span></p>
          <p class="MsoNormal"><span
              style="font-family:&quot;Arial&quot;,sans-serif;color:#172B4D"
              lang="EN-US"><o:p> </o:p></span></p>
          <p class="MsoNormal"><span
style="font-family:&quot;Arial&quot;,sans-serif;color:#172B4D;background:white"
              lang="EN-US">Would it better to return -1 in
              FileChannel.transferFrom/transferFromArbitraryChannel when
              src.read returns -1 and tw is 0?<o:p></o:p></span></p>
          <br>
        </div>
      </blockquote>
      Hi Hamlin,<br>
      <br>
      The transferFrom method returns the number of bytes written to the
      file. Changing the spec to allow it return -1 would be an
      incompatible change and could potentially break usages that keep a
      running total of bytes transferred.<br>
    </blockquote>
    <p>Hi Alan,</p>
    <p>Yes, I think so too. But still like to see if we can improve it a
      little bit.<br>
    </p>
    <blockquote type="cite"
      cite="mid:f0d14384-b663-7398-439d-fd2657470617@oracle.com"> <br>
      Can you expand a bit on the scenario? If the underlying connection
      has been reset or there is another error then I would expect the
      read from the source channel to fail (SocketException "connection
      reset" for example). This is different to the peer closing the
      connection gracefully where reading from the source channel
      returns -1/EOF and there are no bytes written to the file.<br>
    </blockquote>
    <p>Here is a simple demo, I don't use FileChannel.transferFrom
      directly, but I hope I can clarify the situation.</p>
    <p>When ServerHangHttp and Client are up for a while (please check
      the bottom), no matter Server close the socket explicitly or kill
      by "kill -9 xxx", the client side will print out "[client] read :
      -1" continuously. so, if we are using FileChannel.transferFrom
      which will call transferFromArbitraryChannel which will call
      ReadableByteChannel.read, ReadableByteChannel.read will return -1,
      but transferFromArbitraryChannel will return 0, so as
      FileChannel.transferFrom. Based on this return value, following
      while loop will be a infinite loop, and user don't want to call
      something like "call sth like srcSocketChannel.read(...)", please
      check the reason in comments below.<br>
    </p>
    <pre style="white-space: pre-wrap; color: rgb(0, 0, 0); font-style: normal; \
font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; \
letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; \
text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; \
text-decoration-thickness: initial; text-decoration-style: initial; \
text-decoration-color: initial;">while (srcSocketChannel.isOpen()) {  long l = \
fileChannel.transferFrom(srcSocketChannel,...);  // user could call sth like \
srcSocketChannel.read(...), and expect it return -1, and break the loop, but it will \
be unacceptable for some program, where they would like to very quick copy, so called \
"zero" copy through fileChannel.transferFrom, and they don't want to add an extra \
check like "srcSocketChannel.read(...)"  if (l == -1) { // break out the while loop }
}</pre>
    <p>At this situation, I think it's more friendly to have
      fileChannel.transferFrom returns -1.</p>
    <p>Thanks,</p>
    <p>Hamlin</p>
    <p>=========== ServerHangHttp and Client ==============</p>
    <p>public class ServerHangHttp {<br>
              public static void main(String args[]) throws Exception {<br>
                      ServerSocketChannel server =
      ServerSocketChannel.open();<br>
                      server.bind(new InetSocketAddress("127.0.0.1",
      9876));<br>
                      System.out.println("            waiting for
      client...");<br>
                      SocketChannel client = server.accept();<br>
                      System.out.println("            get client
      connection successfully");<br>
                      System.out.println("            socket: " +
      client);<br>
                      int i = 0;<br>
                      while (client.isOpen()) {<br>
                              System.out.println("            write some
      bytes to client");<br>
                             
      client.write(ByteBuffer.wrap("abc".getBytes()));<br>
                              Thread.sleep(1000);<br>
                              /*<br>
                               * if (++i == 10) {<br>
                                      System.out.println("           
      socket is closed");<br>
                                      client.close();<br>
                                      break;<br>
                              }*/<br>
                      }<br>
      <br>
              }<br>
      }<br>
    </p>
    <p>public class Client {<br>
              public static void main(String args[]) throws Exception {<br>
                      SocketChannel client = SocketChannel.open(new
      InetSocketAddress("127.0.0.1", 9876));<br>
                      System.out.println("[client] socket: " + client);<br>
                      int i = 0;<br>
                      ByteBuffer buf = ByteBuffer.allocate(1000);<br>
                      while (true) {<br>
                              int x = client.read(buf);<br>
                              System.out.println("[client] read : " +
      x);<br>
                              Thread.sleep(1000);<br>
                      }<br>
              }<br>
      }</p>
    <p><br>
    </p>
    <blockquote type="cite"
      cite="mid:f0d14384-b663-7398-439d-fd2657470617@oracle.com"> <br>
      -Alan.<br>
      <br>
    </blockquote>
  </body>
</html>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic