Permalink
Browse files

use a more naive streaming approach. ignorance is bliss

  • Loading branch information...
1 parent 5a909bd commit d6cbdc333086c0c4bcdaf45b812126f9f94d912a @mojombo committed Oct 18, 2008
Showing with 47 additions and 201 deletions.
  1. +1 −1 bin/egitd
  2. +1 −1 egitd.conf
  3. +1 −1 elibs/conf.erl
  4. +1 −1 elibs/{re.erl → reg.erl}
  5. +43 −197 elibs/upload_pack.erl
View
@@ -5,7 +5,7 @@ require 'optparse'
DEFAULT_ERLANG_CODEPATHS = %w[ebin]
def rel(path)
- File.join(File.join(File.dirname(__FILE__), *%w[..]), path)
+ File.expand_path(File.join(File.dirname(__FILE__), "..", path))
end
def code_paths
View
@@ -1,3 +1,3 @@
-volcano (.+)/(.+) "/Users/tom/dev/sandbox/git/" ++ conf:hexmod8(Match1) ++ "/" ++ conf:md5_namespace3(Match1) ++ "/" ++ Match1 ++ "/" ++ Match2.
+solid.local (.+)/(.+) "/Users/tom/dev/sandbox/git/" ++ conf:hexmod8(Match1) ++ "/" ++ conf:md5_namespace3(Match1) ++ "/" ++ Match1 ++ "/" ++ Match2.
github.com ([^/]*) "/data/git/repositories/" ++ Match1.
gist.github.com (.*)\.git "/data/git/gists/" ++ conf:namespace3(Match1) ++ "/" ++ Match1 ++ ".git".
View
@@ -10,7 +10,7 @@ read_conf(Conf) ->
convert_path(Host, Path) ->
[{Host, {Regex, Transform}}] = ets:lookup(db, Host),
- case re:smatch(Path, Regex) of
+ case reg:smatch(Path, Regex) of
{match, _A, _B, _C, MatchesTuple} ->
Matches = tuple_to_list(MatchesTuple),
Binding = create_binding(Matches),
@@ -4,7 +4,7 @@
%% 2) put pos+char in global state arg (no noticable difference)
%% 3) get look-ahead character for proper eol (- 5-10% slower)
--module(re).
+-module(reg).
-export([parse/1,match/2,first_match/2,matches/2,sub/3,gsub/3,split/2]).
-export([smatch/2,first_smatch/2]).
View
@@ -1,8 +1,8 @@
-module(upload_pack).
-export([handle/3]).
--define(READ_SOCKET_TIMEOUT, 10000).
--define(READ_PORT_TIMEOUT, 60000).
+-define(READ_SOCKET_TIMEOUT, 10).
+-define(READ_PORT_TIMEOUT, 100).
%****************************************************************************
%
@@ -74,214 +74,60 @@ export_ok(Sock, Host, Path, FullPath) ->
end.
% Create the port to 'git upload-pack'.
-make_port(Sock, Host, Path, FullPath) ->
+make_port(Sock, _Host, _Path, FullPath) ->
Command = "git upload-pack " ++ FullPath,
Port = open_port({spawn, Command}, [binary]),
- send_response_to_client(more, pipe:new(), pipe:new(), Port, Sock, Host, Path, []).
-
-% Send a response to the client
-send_response_to_client(Status, RequestPipe, ResponsePipe, Port, Sock, Host, Path, FullRequest) ->
- % io:format("send response~n"),
- try
- stream_out(Port, Sock, ResponsePipe)
- catch
- throw:{error, timeout} -> ok
- end,
- case Status of
- more ->
- get_request_from_client(RequestPipe, ResponsePipe, Port, Sock, Host, Path, FullRequest);
- done ->
- ok = gen_tcp:close(Sock),
- safe_port_close(Port)
- end.
+ send_port_to_socket(Port, Sock).
-% Read a request from a client
-get_request_from_client(RequestPipe, ResponsePipe, Port, Sock, Host, Path, FullRequest) ->
- % io:format("get request~n"),
- case gather_request(Sock, RequestPipe) of
- {Status, Request, RequestPipe2} ->
- % io:format("req = ~p~n", [Request]),
- FullRequest2 = [Request | FullRequest],
- case Status of
- more -> ok;
- done -> log_request(string:join(lists:reverse(FullRequest), ""), Host, Path)
- end,
- port_command(Port, Request),
- case pipe:size(RequestPipe2) > 0 of
- true ->
- get_request_from_client(RequestPipe2, ResponsePipe, Port, Sock, Host, Path, FullRequest2);
- false ->
- send_response_to_client(Status, RequestPipe2, ResponsePipe, Port, Sock, Host, Path, FullRequest2)
+% Send output from port to socket
+send_port_to_socket(Port, Sock) ->
+ receive
+ {Port, {data, Data}} ->
+ % io:format("port(~p) = ~p~n", [erlang:size(Data), Data]),
+ gen_tcp:send(Sock, Data),
+ case erlang:size(Data) of
+ 16384 ->
+ send_port_to_socket(Port, Sock);
+ _SizeElse ->
+ case last_byte(Data) of
+ 10 ->
+ send_port_to_socket(Port, Sock);
+ 13 ->
+ send_port_to_socket(Port, Sock);
+ _ByteElse ->
+ send_socket_to_port(Port, Sock)
+ end
end;
- {error, closed} ->
- % io:format("socket closed~n"),
- ok = gen_tcp:close(Sock),
- safe_port_close(Port);
- {error, Reason} ->
- error_logger:error_msg("Client closed socket because: ~p~n", [Reason]),
- ok = gen_tcp:close(Sock),
- safe_port_close(Port)
- end.
-
-%****************************************************************************
-%
-% Utility functions
-%
-%****************************************************************************
-
-% Safely unlink and close the port. If the port is not open, this is a noop.
-safe_port_close(Port) ->
- unlink(Port),
- try port_close(Port)
- catch
- _:_ -> ok
- end.
-
-%****************************************************************************
-% gather_request
-
-gather_request(Sock, Pipe) ->
- gather_request(Sock, [], Pipe).
-gather_request(Sock, DataSoFar, Pipe) ->
- try
- {ok, Data, P2} = read_chunk_from_socket(Sock, Pipe),
- % io:format("~p~n", [Data]),
- TotalData = lists:append(DataSoFar, [Data]),
- if
- Data =:= <<"0000">> ->
- {more, binary_to_list(list_to_binary(TotalData)), P2};
- Data =:= <<"0009done\n">> ->
- {done, binary_to_list(list_to_binary(TotalData)), P2};
- true ->
- gather_request(Sock, TotalData, P2)
- end
- catch
- _:_ -> {error, closed}
- end.
-
-%****************************************************************************
-% stream_out
-
-stream_out(Port, Sock, Pipe) ->
- % io:format("stream out "),
- {ok, Data, P2} = read_chunk(Port, Pipe),
- % io:format("~p~n", [Data]),
- gen_tcp:send(Sock, Data),
- case Data =:= <<"0000">> of
- true -> done;
- false -> stream_out(Port, Sock, P2)
- end.
-
-%****************************************************************************
-% read_chunk_from_socket
-
-read_chunk_from_socket(Sock, Pipe) ->
- case pipe:size(Pipe) >= 4 of
- true ->
- {ok, ChunkSizeHex, P2} = pipe:read(4, Pipe),
- % io:format("chunk size hex = ~p~n", [ChunkSizeHex]),
- read_chunk_body_from_socket(ChunkSizeHex, Sock, P2);
- false ->
- {data, Data} = read_from_socket(Sock),
- {ok, P2} = pipe:write(Data, Pipe),
- read_chunk_from_socket(Sock, P2)
+ Msg ->
+ error_logger:error_msg("unknown message ~p~n", [Msg]),
+ send_socket_to_port(Port, Sock)
+ after ?READ_PORT_TIMEOUT ->
+ error_logger:error_msg("timed out waiting for port~n"),
+ send_socket_to_port(Port, Sock)
end.
-read_chunk_body_from_socket(<<"0000">>, _Sock, Pipe) ->
- {ok, <<"0000">>, Pipe};
-
-read_chunk_body_from_socket(ChunkSizeHex, Sock, Pipe) ->
- ChunkSize = convert_chunk_size(ChunkSizeHex),
- % io:format("chunk size = ~p~n", [ChunkSize]),
- case pipe:read(ChunkSize, Pipe) of
- {ok, Bin, P2} ->
- % io:format("chunk body = ~p~n", [Bin]),
- Data = concat_binary([ChunkSizeHex, Bin]),
- {ok, Data, P2};
- eof ->
- % io:format("chunk body eof~n", []),
- {data, Data} = read_from_socket(Sock),
- {ok, P2} = pipe:write(Data, Pipe),
- read_chunk_body_from_socket(ChunkSizeHex, Sock, P2)
- end.
-
-read_from_socket(Sock) ->
+% Send input from socket to port
+send_socket_to_port(Port, Sock) ->
case gen_tcp:recv(Sock, 0, ?READ_SOCKET_TIMEOUT) of
{ok, Data} ->
% io:format("socket = ~p~n", [Data]),
- {data, list_to_binary(Data)};
+ port_command(Port, Data),
+ send_port_to_socket(Port, Sock);
+ {error, timeout} ->
+ error_logger:error_msg("read socket timeout~n", []),
+ send_port_to_socket(Port, Sock);
{error, Reason} ->
- {error, Reason}
+ error_logger:error_msg("read socket error ~p~n", [Reason])
end.
-
-%****************************************************************************
-% read_chunk (port)
-read_chunk(Port, Pipe) ->
- case pipe:size(Pipe) >= 4 of
- true ->
- {ok, ChunkSizeHex, P2} = pipe:read(4, Pipe),
- % io:format("chunk size hex = ~p~n", [ChunkSizeHex]),
- read_chunk_body(ChunkSizeHex, Port, P2);
- false ->
- {data, Data} = readline(Port),
- {ok, P2} = pipe:write(Data, Pipe),
- read_chunk(Port, P2)
- end.
-
-read_chunk_body(<<"0000">>, _Port, Pipe) ->
- {ok, <<"0000">>, Pipe};
-
-read_chunk_body(ChunkSizeHex, Port, Pipe) ->
- ChunkSize = convert_chunk_size(ChunkSizeHex),
- % io:format("chunk size = ~p~n", [ChunkSize]),
- case pipe:read(ChunkSize, Pipe) of
- {ok, Bin, P2} ->
- % io:format("chunk body = ~p~n", [Bin]),
- Data = concat_binary([ChunkSizeHex, Bin]),
- {ok, Data, P2};
- eof ->
- % io:format("chunk body eof~n", []),
- {data, Data} = readline(Port),
- {ok, P2} = pipe:write(Data, Pipe),
- read_chunk_body(ChunkSizeHex, Port, P2)
- end.
-
-convert_chunk_size(ChunkSizeHex) ->
- {ok, [Size], []} = io_lib:fread("~16u", binary_to_list(ChunkSizeHex)),
- Size - 4.
-
-readline(Port) ->
- receive
- {Port, {data, Data}} ->
- % io:format("port = ~p~n", [Data]),
- {data, Data};
- Msg ->
- error_logger:error_msg("unknown message ~p~n", [Msg]),
- {error, Msg}
- after ?READ_PORT_TIMEOUT ->
- error_logger:error_msg("timed out waiting for port~n"),
- throw({error, timeout})
- end.
-
-log_request(Request, Host, Path) ->
- case regexp:first_match(Request, "^....want") of
- {match ,_Start, _Length} ->
- log_initial_clone(Request, Host, Path);
- _Else ->
- ok
- end.
-
-log_initial_clone(Request, Host, Path) ->
- case regexp:first_match(Request, "have") of
- {match ,_Start, _Length} ->
- ok;
- _Else ->
- ok = log:write("clone", [Host, Path])
- end.
-
file_exists(FullPath) ->
case file:read_file_info(FullPath) of
{ok, _Info} -> true;
{error, _Reason} -> false
- end.
+ end.
+
+last_byte(Bin) ->
+ Size = erlang:size(Bin),
+ {_B1, B2} = split_binary(Bin, Size - 1),
+ [Byte] = binary_to_list(B2),
+ Byte.

0 comments on commit d6cbdc3

Please sign in to comment.