[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:"Arial",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:"Arial",sans-serif;color:#172B4D"
lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span
style="font-family:"Arial",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