From 54bdd9a15d2e130c76f76ca322af56b306d02078 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 9 Nov 2011 11:52:14 +0100 Subject: Implement blocking calls for sendfile Move sendfile data to invoke data instead of file_descr. Remove usage of ready_output when doing a send. If told to send 0 bytes, file_sendfile now sends the entire file for linux. --- lib/kernel/src/gen_tcp.erl | 23 ++++++-------- lib/kernel/test/gen_tcp_api_SUITE.erl | 59 +++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 33 deletions(-) (limited to 'lib/kernel') diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index ea25dc3dc3..26afed4ff9 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -314,14 +314,14 @@ unrecv(S, Data) when is_port(S) -> %% Send data using sendfile %% --define(MAX_CHUNK_SIZE, (1 bsl 30)*2-1). +-define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory -spec sendfile(File, Sock, Offset, Bytes, Opts) -> {'ok', non_neg_integer()} | {'error', inet:posix()} when File :: file:io_device(), Sock :: socket(), - Offset :: non_neg_integer() | undefined, - Bytes :: non_neg_integer() | undefined, + Offset :: non_neg_integer(), + Bytes :: non_neg_integer(), Opts :: [sendfile_option()]. sendfile(File, Sock, Offset, Bytes, Opts) when is_pid(File) -> Ref = erlang:monitor(process, File), @@ -359,8 +359,7 @@ sendfile(File, Sock) -> {error, Reason} -> {error, Reason}; {ok, Fd} -> - {ok, #file_info{size = Bytes}} = file:read_file_info(File), - Res = sendfile(Fd, Sock, 0, Bytes, []), + Res = sendfile(Fd, Sock, 0, 0, []), file:close(Fd), Res end. @@ -461,21 +460,17 @@ sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) -> end. -sendfile_fallback(File, Sock, undefined, Bytes, ChunkSize) -> - sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0); sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) -> - {ok, CurrPos} = file:position(File, 0), + {ok, CurrPos} = file:position(File, {cur, 0}), {ok, _NewPos} = file:position(File, {bof, Offset}), Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0), file:position(File, {bof, CurrPos}), Res. -sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) -> - {ok, BytesSent}; sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent) - when Bytes > BytesSent; Bytes == undefined -> - Size = if Bytes == undefined -> + when Bytes > BytesSent; Bytes == 0 -> + Size = if Bytes == 0 -> ChunkSize; (Bytes - BytesSent + ChunkSize) > 0 -> Bytes - BytesSent; @@ -496,7 +491,9 @@ sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent) {ok, BytesSent}; Error -> Error - end. + end; +sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) -> + {ok, BytesSent}. sendfile_send(Sock, Data, Old) -> Len = iolist_size(Data), diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 492c60f521..60a3dcb2f4 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -34,7 +34,8 @@ t_recv_timeout/1, t_recv_eof/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, t_fdopen/1, t_implicit_inet6/1, - t_sendfile/0, t_sendfile/1, t_sendfile_hdtl/1, t_sendfile_partial/1, + t_sendfile_small/1, t_sendfile_big/1, + t_sendfile_hdtl/1, t_sendfile_partial/1, t_sendfile_offset/1]). -export([sendfile_server/1]). @@ -56,7 +57,8 @@ groups() -> {t_sendfile_ioserv, [], sendfile_all()}]. sendfile_all() -> - [t_sendfile,t_sendfile_hdtl, t_sendfile_partial, t_sendfile_offset]. +% [t_sendfile,t_sendfile_hdtl, t_sendfile_partial, t_sendfile_offset]. + [t_sendfile_big]. init_per_suite(Config) -> Config. @@ -66,19 +68,25 @@ end_per_suite(_Config) -> init_per_group(t_sendfile, Config) -> Priv = ?config(priv_dir, Config), - Filename = filename:join(Priv, "sendfile_small.html"), - {ok, D} = file:open(Filename,[write]), - io:format(D,"yo baby yo",[]), - file:sync(D), - file:close(D), - [{small_file, Filename}|Config]; + SFilename = filename:join(Priv, "sendfile_small.html"), + {ok, DS} = file:open(SFilename,[write]), + io:format(DS,"yo baby yo",[]), + file:sync(DS), + file:close(DS), + BFilename = filename:join(Priv, "sendfile_big.html"), + {ok, DB} = file:open(BFilename,[write,raw]), + [file:write(DB,[<<0:(10*8*1024*1024)>>]) || + _I <- lists:seq(1,51)], + file:sync(DB), + file:close(DB), + [{small_file, SFilename},{big_file, BFilename}|Config]; init_per_group(t_sendfile_raw, Config) -> [{file_opts, [raw]}|Config]; init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> - Config. + file:delete(proplists:get_value(big_file, Config)). init_per_testcase(_Func, Config) -> @@ -258,12 +266,19 @@ implicit_inet6(S, Addr) -> ?line ok = gen_tcp:close(S2), ?line ok = gen_tcp:close(S1). +t_sendfile_small(Config) when is_list(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock) -> + {Size, Data} = sendfile_file_info(Filename), + {ok, Size} = gen_tcp:sendfile(Filename, Sock), + Data + end, -t_sendfile() -> - [{timetrap, {seconds, 5}}]. + ok = sendfile_send(Send). -t_sendfile(Config) when is_list(Config) -> - Filename = proplists:get_value(small_file, Config), +t_sendfile_big(Config) when is_list(Config) -> + Filename = proplists:get_value(big_file, Config), Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), @@ -281,7 +296,7 @@ t_sendfile_partial(Config) -> {_Size, <>} = sendfile_file_info(Filename), {ok,D} = file:open(Filename,[read|FileOpts]), - {ok,5} = gen_tcp:sendfile(D,Sock,undefined,5,[]), + {ok,5} = gen_tcp:sendfile(D,Sock,0,5,[]), file:close(D), Data end, @@ -289,20 +304,24 @@ t_sendfile_partial(Config) -> {_Size, <>} = sendfile_file_info(Filename), - {ok,D} = file:open(Filename,[read|FileOpts]), + {ok,D} = file:open(Filename,[read,binary|FileOpts]), + {ok, <>} = file:read(D,5), FSend = fun(Sock) -> - {ok,5} = gen_tcp:sendfile(D,Sock,undefined,5,[]), + {ok,5} = gen_tcp:sendfile(D,Sock,0,5,[]), FData end, ok = sendfile_send(FSend), SSend = fun(Sock) -> - {ok,3} = gen_tcp:sendfile(D,Sock,undefined,3,[]), + {ok,3} = gen_tcp:sendfile(D,Sock,5,3,[]), SData end, ok = sendfile_send(SSend), + + {ok, <>} = file:read(D,3), + file:close(D). t_sendfile_offset(Config) -> @@ -330,7 +349,7 @@ t_sendfile_hdtl(Config) -> {ok,D} = file:open(Filename,[read|FileOpts]), AllSize = Size+HdtlSize, {ok, AllSize} = gen_tcp:sendfile( - D, Sock,undefined,undefined, + D, Sock,0,0, [{headers,Headers}, {trailers,Trailers}]), file:close(D), @@ -356,9 +375,9 @@ t_sendfile_hdtl(Config) -> SendTl = fun(Sock) -> Trailers = [<<"trailer1">>,"trailer2"], - D = Send(Sock,Trailers,undefined, + D = Send(Sock,undefined,Trailers, iolist_size([Trailers])), - iolist_to_binary([Trailers,D]) + iolist_to_binary([D,Trailers]) end, ok = sendfile_send(SendTl). -- cgit v1.2.3