Modified: incubator/thrift/trunk/lib/erl/src/thrift_processor.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_processor.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_processor.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_processor.erl Mon Aug 30 22:05:00 2010 @@ -24,54 +24,55 @@ -include("thrift_constants.hrl"). -include("thrift_protocol.hrl"). --record(thrift_processor, {handler, protocol, service}). +-record(thrift_processor, {handler, in_protocol, out_protocol, service}). -init({_Server, ProtoGen, Service, Handler}) when is_function(ProtoGen, 0) -> - {ok, Proto} = ProtoGen(), - loop(#thrift_processor{protocol = Proto, +init({Server, ProtoGen, Service, Handler}) when is_function(ProtoGen, 0) -> + {ok, IProt, OProt} = ProtoGen(), + loop(#thrift_processor{in_protocol = IProt, + out_protocol = OProt, service = Service, handler = Handler}). -loop(State0 = #thrift_processor{protocol = Proto0}) -> - {Proto1, MessageBegin} = thrift_protocol:read(Proto0, message_begin), - State1 = State0#thrift_processor{protocol = Proto1}, - case MessageBegin of +loop(State = #thrift_processor{in_protocol = IProto, + out_protocol = OProto}) -> + case thrift_protocol:read(IProto, message_begin) of #protocol_message_begin{name = Function, type = ?tMessageType_CALL} -> - {State2, ok} = handle_function(State1, list_to_atom(Function)), - loop(State2); + ok = handle_function(State, list_to_atom(Function)), + loop(State); #protocol_message_begin{name = Function, type = ?tMessageType_ONEWAY} -> - {State2, ok} = handle_function(State1, list_to_atom(Function)), - loop(State2); + ok = handle_function(State, list_to_atom(Function)), + loop(State); {error, timeout} -> - thrift_protocol:close_transport(Proto1), + thrift_protocol:close_transport(OProto), ok; {error, closed} -> %% error_logger:info_msg("Client disconnected~n"), - thrift_protocol:close_transport(Proto1), + thrift_protocol:close_transport(OProto), exit(shutdown) end. -handle_function(State0=#thrift_processor{protocol = Proto0, - handler = Handler, - service = Service}, +handle_function(State=#thrift_processor{in_protocol = IProto, + out_protocol = OProto, + handler = Handler, + service = Service}, Function) -> InParams = Service:function_info(Function, params_type), - {Proto1, {ok, Params}} = thrift_protocol:read(Proto0, InParams), - State1 = State0#thrift_processor{protocol = Proto1}, + {ok, Params} = thrift_protocol:read(IProto, InParams), try Result = Handler:handle_function(Function, Params), %% {Micro, Result} = better_timer(Handler, handle_function, [Function, Params]), %% error_logger:info_msg("Processed ~p(~p) in ~.4fms~n", %% [Function, Params, Micro/1000.0]), - handle_success(State1, Function, Result) + handle_success(State, Function, Result) catch - Type:Data when Type =:= throw orelse Type =:= error -> - handle_function_catch(State1, Function, Type, Data) - end. + Type:Data -> + handle_function_catch(State, Function, Type, Data) + end, + after_reply(OProto). handle_function_catch(State = #thrift_processor{service = Service}, Function, ErrType, ErrData) -> @@ -83,37 +84,39 @@ handle_function_catch(State = #thrift_pr error_logger:warning_msg( "oneway void ~p threw error which must be ignored: ~p", [Function, {ErrType, ErrData, Stack}]), - {State, ok}; + ok; {throw, Exception} when is_tuple(Exception), size(Exception) > 0 -> - %error_logger:warning_msg("~p threw exception: ~p~n", [Function, Exception]), - handle_exception(State, Function, Exception); - % we still want to accept more requests from this client + error_logger:warning_msg("~p threw exception: ~p~n", [Function, Exception]), + handle_exception(State, Function, Exception), + ok; % we still want to accept more requests from this client {error, Error} -> - handle_error(State, Function, Error) + ok = handle_error(State, Function, Error) end. -handle_success(State = #thrift_processor{service = Service}, +handle_success(State = #thrift_processor{out_protocol = OProto, + service = Service}, Function, Result) -> ReplyType = Service:function_info(Function, reply_type), StructName = atom_to_list(Function) ++ "_result", - case Result of - {reply, ReplyData} -> - Reply = {{struct, [{0, ReplyType}]}, {StructName, ReplyData}}, - send_reply(State, Function, ?tMessageType_REPLY, Reply); - - ok when ReplyType == {struct, []} -> - send_reply(State, Function, ?tMessageType_REPLY, {ReplyType, {StructName}}); - - ok when ReplyType == oneway_void -> - %% no reply for oneway void - {State, ok} - end. + ok = case Result of + {reply, ReplyData} -> + Reply = {{struct, [{0, ReplyType}]}, {StructName, ReplyData}}, + send_reply(OProto, Function, ?tMessageType_REPLY, Reply); + + ok when ReplyType == {struct, []} -> + send_reply(OProto, Function, ?tMessageType_REPLY, {ReplyType, {StructName}}); + + ok when ReplyType == oneway_void -> + %% no reply for oneway void + ok + end. -handle_exception(State = #thrift_processor{service = Service}, +handle_exception(State = #thrift_processor{out_protocol = OProto, + service = Service}, Function, Exception) -> ExceptionType = element(1, Exception), @@ -138,9 +141,9 @@ handle_exception(State = #thrift_process % Make sure we got at least one defined case lists:all(fun(X) -> X =:= undefined end, ExceptionList) of true -> - handle_unknown_exception(State, Function, Exception); + ok = handle_unknown_exception(State, Function, Exception); false -> - send_reply(State, Function, ?tMessageType_REPLY, {ReplySpec, ExceptionTuple}) + ok = send_reply(OProto, Function, ?tMessageType_REPLY, {ReplySpec, ExceptionTuple}) end. %% @@ -151,7 +154,7 @@ handle_unknown_exception(State, Function handle_error(State, Function, {exception_not_declared_as_thrown, Exception}). -handle_error(State, Function, Error) -> +handle_error(#thrift_processor{out_protocol = OProto}, Function, Error) -> Stack = erlang:get_stacktrace(), error_logger:error_msg("~p had an error: ~p~n", [Function, {Error, Stack}]), @@ -167,14 +170,19 @@ handle_error(State, Function, Error) -> #'TApplicationException'{ message = Message, type = ?TApplicationException_UNKNOWN}}, - send_reply(State, Function, ?tMessageType_EXCEPTION, Reply). + send_reply(OProto, Function, ?tMessageType_EXCEPTION, Reply). -send_reply(State = #thrift_processor{protocol = Proto0}, Function, ReplyMessageType, Reply) -> - {Proto1, ok} = thrift_protocol:write(Proto0, #protocol_message_begin{ - name = atom_to_list(Function), - type = ReplyMessageType, - seqid = 0}), - {Proto2, ok} = thrift_protocol:write(Proto1, Reply), - {Proto3, ok} = thrift_protocol:write(Proto2, message_end), - {Proto4, ok} = thrift_protocol:flush_transport(Proto3), - {State#thrift_processor{protocol = Proto4}, ok}. +send_reply(OProto, Function, ReplyMessageType, Reply) -> + ok = thrift_protocol:write(OProto, #protocol_message_begin{ + name = atom_to_list(Function), + type = ReplyMessageType, + seqid = 0}), + ok = thrift_protocol:write(OProto, Reply), + ok = thrift_protocol:write(OProto, message_end), + ok = thrift_protocol:flush_transport(OProto), + ok. + +after_reply(OProto) -> + ok = thrift_protocol:flush_transport(OProto) + %% ok = thrift_protocol:close_transport(OProto) + .
Modified: incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_protocol.erl Mon Aug 30 22:05:00 2010 @@ -49,13 +49,10 @@ new(Module, Data) when is_atom(Module) - {ok, #protocol{module = Module, data = Data}}. --spec flush_transport(#protocol{}) -> {#protocol{}, ok}. -flush_transport(Proto = #protocol{module = Module, - data = Data}) -> - {NewData, Result} = Module:flush_transport(Data), - {Proto#protocol{data = NewData}, Result}. +flush_transport(#protocol{module = Module, + data = Data}) -> + Module:flush_transport(Data). --spec close_transport(#protocol{}) -> ok. close_transport(#protocol{module = Module, data = Data}) -> Module:close_transport(Data). @@ -89,8 +86,7 @@ term_to_typeid({list, _}) -> ?tType_LIST %% Structure is like: %% [{Fid, Type}, ...] --spec read(#protocol{}, {struct, _StructDef}, atom()) -> {#protocol{}, {ok, tuple()}}. -read(IProto0, {struct, Structure}, Tag) +read(IProto, {struct, Structure}, Tag) when is_list(Structure), is_atom(Tag) -> % If we want a tagged tuple, we need to offset all the tuple indices @@ -107,23 +103,14 @@ read(IProto0, {struct, Structure}, Tag) % Fid -> {Type, Index} SDict = dict:from_list(SWithIndices), - {IProto1, ok} = read(IProto0, struct_begin), + ok = read(IProto, struct_begin), RTuple0 = erlang:make_tuple(length(Structure) + Offset, undefined), RTuple1 = if Tag =/= undefined -> setelement(1, RTuple0, Tag); true -> RTuple0 end, - {IProto2, RTuple2} = read_struct_loop(IProto1, SDict, RTuple1), - {IProto2, {ok, RTuple2}}. - - -%% NOTE: Keep this in sync with thrift_protocol_behaviour:read --spec read - (#protocol{}, {struct, _Info}) -> {#protocol{}, {ok, tuple()} | {error, _Reason}}; - (#protocol{}, tprot_cont_tag()) -> {#protocol{}, {ok, any()} | {error, _Reason}}; - (#protocol{}, tprot_empty_tag()) -> {#protocol{}, ok | {error, _Reason}}; - (#protocol{}, tprot_header_tag()) -> {#protocol{}, tprot_header_val() | {error, _Reason}}; - (#protocol{}, tprot_data_tag()) -> {#protocol{}, {ok, any()} | {error, _Reason}}. + RTuple2 = read_struct_loop(IProto, SDict, RTuple1), + {ok, RTuple2}. read(IProto, {struct, {Module, StructureName}}) when is_atom(Module), is_atom(StructureName) -> @@ -132,165 +119,137 @@ read(IProto, {struct, {Module, Structure read(IProto, S={struct, Structure}) when is_list(Structure) -> read(IProto, S, undefined); -read(IProto0, {list, Type}) -> - {IProto1, #protocol_list_begin{etype = EType, size = Size}} = - read(IProto0, list_begin), - {EType, EType} = {term_to_typeid(Type), EType}, - {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) -> - {ProtoS1, {ok, Item}} = read(ProtoS0, Type), - {Item, ProtoS1} - end, - IProto1, - lists:duplicate(Size, 0)), - {IProto3, ok} = read(IProto2, list_end), - {IProto3, {ok, List}}; - -read(IProto0, {map, KeyType, ValType}) -> - {IProto1, #protocol_map_begin{size = Size, ktype = KType, vtype = VType}} = - read(IProto0, map_begin), - {KType, KType} = {term_to_typeid(KeyType), KType}, - {VType, VType} = {term_to_typeid(ValType), VType}, - {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) -> - {ProtoS1, {ok, Key}} = read(ProtoS0, KeyType), - {ProtoS2, {ok, Val}} = read(ProtoS1, ValType), - {{Key, Val}, ProtoS2} - end, - IProto1, - lists:duplicate(Size, 0)), - {IProto3, ok} = read(IProto2, map_end), - {IProto3, {ok, dict:from_list(List)}}; - -read(IProto0, {set, Type}) -> - {IProto1, #protocol_set_begin{etype = EType, size = Size}} = - read(IProto0, set_begin), - {EType, EType} = {term_to_typeid(Type), EType}, - {List, IProto2} = lists:mapfoldl(fun(_, ProtoS0) -> - {ProtoS1, {ok, Item}} = read(ProtoS0, Type), - {Item, ProtoS1} - end, - IProto1, - lists:duplicate(Size, 0)), - {IProto3, ok} = read(IProto2, set_end), - {IProto3, {ok, sets:from_list(List)}}; - -read(Protocol, ProtocolType) -> - read_specific(Protocol, ProtocolType). - -%% NOTE: Keep this in sync with thrift_protocol_behaviour:read --spec read_specific - (#protocol{}, tprot_empty_tag()) -> {#protocol{}, ok | {error, _Reason}}; - (#protocol{}, tprot_header_tag()) -> {#protocol{}, tprot_header_val() | {error, _Reason}}; - (#protocol{}, tprot_data_tag()) -> {#protocol{}, {ok, any()} | {error, _Reason}}. -read_specific(Proto = #protocol{module = Module, - data = ModuleData}, ProtocolType) -> - {NewData, Result} = Module:read(ModuleData, ProtocolType), - {Proto#protocol{data = NewData}, Result}. - -read_struct_loop(IProto0, SDict, RTuple) -> - {IProto1, #protocol_field_begin{type = FType, id = Fid}} = - thrift_protocol:read(IProto0, field_begin), +read(IProto, {list, Type}) -> + #protocol_list_begin{etype = EType, size = Size} = + read(IProto, list_begin), + List = [Result || {ok, Result} <- + [read(IProto, Type) || _X <- lists:duplicate(Size, 0)]], + ok = read(IProto, list_end), + {ok, List}; + +read(IProto, {map, KeyType, ValType}) -> + #protocol_map_begin{size = Size} = + read(IProto, map_begin), + + List = [{Key, Val} || {{ok, Key}, {ok, Val}} <- + [{read(IProto, KeyType), + read(IProto, ValType)} || _X <- lists:duplicate(Size, 0)]], + ok = read(IProto, map_end), + {ok, dict:from_list(List)}; + +read(IProto, {set, Type}) -> + #protocol_set_begin{etype = _EType, + size = Size} = + read(IProto, set_begin), + List = [Result || {ok, Result} <- + [read(IProto, Type) || _X <- lists:duplicate(Size, 0)]], + ok = read(IProto, set_end), + {ok, sets:from_list(List)}; + +read(#protocol{module = Module, + data = ModuleData}, ProtocolType) -> + Module:read(ModuleData, ProtocolType). + +read_struct_loop(IProto, SDict, RTuple) -> + #protocol_field_begin{type = FType, id = Fid, name = Name} = + thrift_protocol:read(IProto, field_begin), case {FType, Fid} of {?tType_STOP, _} -> - {IProto1, RTuple}; + RTuple; _Else -> case dict:find(Fid, SDict) of {ok, {Type, Index}} -> case term_to_typeid(Type) of FType -> - {IProto2, {ok, Val}} = read(IProto1, Type), - {IProto3, ok} = thrift_protocol:read(IProto2, field_end), + {ok, Val} = read(IProto, Type), + thrift_protocol:read(IProto, field_end), NewRTuple = setelement(Index, RTuple, Val), - read_struct_loop(IProto3, SDict, NewRTuple); + read_struct_loop(IProto, SDict, NewRTuple); Expected -> error_logger:info_msg( "Skipping field ~p with wrong type (~p != ~p)~n", [Fid, FType, Expected]), - skip_field(FType, IProto1, SDict, RTuple) + skip_field(FType, IProto, SDict, RTuple) end; _Else2 -> error_logger:info_msg("Skipping field ~p with unknown fid~n", [Fid]), - skip_field(FType, IProto1, SDict, RTuple) + skip_field(FType, IProto, SDict, RTuple) end end. -skip_field(FType, IProto0, SDict, RTuple) -> +skip_field(FType, IProto, SDict, RTuple) -> FTypeAtom = thrift_protocol:typeid_to_atom(FType), - {IProto1, ok} = thrift_protocol:skip(IProto0, FTypeAtom), - {IProto2, ok} = read(IProto1, field_end), - read_struct_loop(IProto2, SDict, RTuple). - --spec skip(#protocol{}, any()) -> {#protocol{}, ok}. - -skip(Proto0, struct) -> - {Proto1, ok} = read(Proto0, struct_begin), - {Proto2, ok} = skip_struct_loop(Proto1), - {Proto3, ok} = read(Proto2, struct_end), - {Proto3, ok}; - -skip(Proto0, map) -> - {Proto1, Map} = read(Proto0, map_begin), - {Proto2, ok} = skip_map_loop(Proto1, Map), - {Proto3, ok} = read(Proto2, map_end), - {Proto3, ok}; - -skip(Proto0, set) -> - {Proto1, Set} = read(Proto0, set_begin), - {Proto2, ok} = skip_set_loop(Proto1, Set), - {Proto3, ok} = read(Proto2, set_end), - {Proto3, ok}; - -skip(Proto0, list) -> - {Proto1, List} = read(Proto0, list_begin), - {Proto2, ok} = skip_list_loop(Proto1, List), - {Proto3, ok} = read(Proto2, list_end), - {Proto3, ok}; - -skip(Proto0, Type) when is_atom(Type) -> - {Proto1, _Ignore} = read(Proto0, Type), - {Proto1, ok}. + thrift_protocol:skip(IProto, FTypeAtom), + read(IProto, field_end), + read_struct_loop(IProto, SDict, RTuple). + + +skip(Proto, struct) -> + ok = read(Proto, struct_begin), + ok = skip_struct_loop(Proto), + ok = read(Proto, struct_end); + +skip(Proto, map) -> + Map = read(Proto, map_begin), + ok = skip_map_loop(Proto, Map), + ok = read(Proto, map_end); + +skip(Proto, set) -> + Set = read(Proto, set_begin), + ok = skip_set_loop(Proto, Set), + ok = read(Proto, set_end); + +skip(Proto, list) -> + List = read(Proto, list_begin), + ok = skip_list_loop(Proto, List), + ok = read(Proto, list_end); + +skip(Proto, Type) when is_atom(Type) -> + _Ignore = read(Proto, Type), + ok. -skip_struct_loop(Proto0) -> - {Proto1, #protocol_field_begin{type = Type}} = read(Proto0, field_begin), +skip_struct_loop(Proto) -> + #protocol_field_begin{type = Type} = read(Proto, field_begin), case Type of ?tType_STOP -> - {Proto1, ok}; + ok; _Else -> - {Proto2, ok} = skip(Proto1, Type), - {Proto3, ok} = read(Proto2, field_end), - skip_struct_loop(Proto3) + skip(Proto, Type), + ok = read(Proto, field_end), + skip_struct_loop(Proto) end. -skip_map_loop(Proto0, Map = #protocol_map_begin{ktype = Ktype, - vtype = Vtype, - size = Size}) -> +skip_map_loop(Proto, Map = #protocol_map_begin{ktype = Ktype, + vtype = Vtype, + size = Size}) -> case Size of N when N > 0 -> - {Proto1, ok} = skip(Proto0, Ktype), - {Proto2, ok} = skip(Proto1, Vtype), - skip_map_loop(Proto2, + skip(Proto, Ktype), + skip(Proto, Vtype), + skip_map_loop(Proto, Map#protocol_map_begin{size = Size - 1}); - 0 -> {Proto0, ok} + 0 -> ok end. -skip_set_loop(Proto0, Map = #protocol_set_begin{etype = Etype, - size = Size}) -> +skip_set_loop(Proto, Map = #protocol_set_begin{etype = Etype, + size = Size}) -> case Size of N when N > 0 -> - {Proto1, ok} = skip(Proto0, Etype), - skip_set_loop(Proto1, + skip(Proto, Etype), + skip_set_loop(Proto, Map#protocol_set_begin{size = Size - 1}); - 0 -> {Proto0, ok} + 0 -> ok end. -skip_list_loop(Proto0, Map = #protocol_list_begin{etype = Etype, - size = Size}) -> +skip_list_loop(Proto, Map = #protocol_list_begin{etype = Etype, + size = Size}) -> case Size of N when N > 0 -> - {Proto1, ok} = skip(Proto0, Etype), - skip_list_loop(Proto1, + skip(Proto, Etype), + skip_list_loop(Proto, Map#protocol_list_begin{size = Size - 1}); - 0 -> {Proto0, ok} + 0 -> ok end. @@ -308,95 +267,90 @@ skip_list_loop(Proto0, Map = #protocol_l %% | list() -- for list %% | dictionary() -- for map %% | set() -- for set -%% | any() -- for base types +%% | term() -- for base types %% %% Description: %%-------------------------------------------------------------------- --spec write(#protocol{}, any()) -> {#protocol{}, ok | {error, _Reason}}. - -write(Proto0, {{struct, StructDef}, Data}) +write(Proto, {{struct, StructDef}, Data}) when is_list(StructDef), is_tuple(Data), length(StructDef) == size(Data) - 1 -> [StructName | Elems] = tuple_to_list(Data), - {Proto1, ok} = write(Proto0, #protocol_struct_begin{name = StructName}), - {Proto2, ok} = struct_write_loop(Proto1, StructDef, Elems), - {Proto3, ok} = write(Proto2, struct_end), - {Proto3, ok}; + ok = write(Proto, #protocol_struct_begin{name = StructName}), + ok = struct_write_loop(Proto, StructDef, Elems), + ok = write(Proto, struct_end), + ok; write(Proto, {{struct, {Module, StructureName}}, Data}) when is_atom(Module), is_atom(StructureName), element(1, Data) =:= StructureName -> + StructType = Module:struct_info(StructureName), write(Proto, {Module:struct_info(StructureName), Data}); -write(Proto0, {{list, Type}, Data}) +write(Proto, {{list, Type}, Data}) when is_list(Data) -> - {Proto1, ok} = write(Proto0, + ok = write(Proto, #protocol_list_begin{ etype = term_to_typeid(Type), size = length(Data) }), - Proto2 = lists:foldl(fun(Elem, ProtoIn) -> - {ProtoOut, ok} = write(ProtoIn, {Type, Elem}), - ProtoOut - end, - Proto1, - Data), - {Proto3, ok} = write(Proto2, list_end), - {Proto3, ok}; - -write(Proto0, {{map, KeyType, ValType}, Data}) -> - {Proto1, ok} = write(Proto0, - #protocol_map_begin{ - ktype = term_to_typeid(KeyType), - vtype = term_to_typeid(ValType), - size = dict:size(Data) - }), - Proto2 = dict:fold(fun(KeyData, ValData, ProtoS0) -> - {ProtoS1, ok} = write(ProtoS0, {KeyType, KeyData}), - {ProtoS2, ok} = write(ProtoS1, {ValType, ValData}), - ProtoS2 - end, - Proto1, - Data), - {Proto3, ok} = write(Proto2, map_end), - {Proto3, ok}; + lists:foreach(fun(Elem) -> + ok = write(Proto, {Type, Elem}) + end, + Data), + ok = write(Proto, list_end), + ok; + +write(Proto, {{map, KeyType, ValType}, Data}) -> + ok = write(Proto, + #protocol_map_begin{ + ktype = term_to_typeid(KeyType), + vtype = term_to_typeid(ValType), + size = dict:size(Data) + }), + dict:fold(fun(KeyData, ValData, _Acc) -> + ok = write(Proto, {KeyType, KeyData}), + ok = write(Proto, {ValType, ValData}) + end, + _AccO = ok, + Data), + ok = write(Proto, map_end), + ok; -write(Proto0, {{set, Type}, Data}) -> +write(Proto, {{set, Type}, Data}) -> true = sets:is_set(Data), - {Proto1, ok} = write(Proto0, - #protocol_set_begin{ - etype = term_to_typeid(Type), - size = sets:size(Data) - }), - Proto2 = sets:fold(fun(Elem, ProtoIn) -> - {ProtoOut, ok} = write(ProtoIn, {Type, Elem}), - ProtoOut - end, - Proto1, - Data), - {Proto3, ok} = write(Proto2, set_end), - {Proto3, ok}; - -write(Proto = #protocol{module = Module, - data = ModuleData}, Data) -> - {NewData, Result} = Module:write(ModuleData, Data), - {Proto#protocol{data = NewData}, Result}. - -struct_write_loop(Proto0, [{Fid, Type} | RestStructDef], [Data | RestData]) -> - NewProto = case Data of - undefined -> - Proto0; % null fields are skipped in response - _ -> - {Proto1, ok} = write(Proto0, - #protocol_field_begin{ - type = term_to_typeid(Type), - id = Fid - }), - {Proto2, ok} = write(Proto1, {Type, Data}), - {Proto3, ok} = write(Proto2, field_end), - Proto3 - end, - struct_write_loop(NewProto, RestStructDef, RestData); + ok = write(Proto, + #protocol_set_begin{ + etype = term_to_typeid(Type), + size = sets:size(Data) + }), + sets:fold(fun(Elem, _Acc) -> + ok = write(Proto, {Type, Elem}) + end, + _Acc0 = ok, + Data), + ok = write(Proto, set_end), + ok; + +write(#protocol{module = Module, + data = ModuleData}, Data) -> + Module:write(ModuleData, Data). + +struct_write_loop(Proto, [{Fid, Type} | RestStructDef], [Data | RestData]) -> + case Data of + undefined -> + % null fields are skipped in response + skip; + _ -> + ok = write(Proto, + #protocol_field_begin{ + type = term_to_typeid(Type), + id = Fid + }), + ok = write(Proto, {Type, Data}), + ok = write(Proto, field_end) + end, + struct_write_loop(Proto, RestStructDef, RestData); struct_write_loop(Proto, [], []) -> - write(Proto, field_stop). + ok = write(Proto, field_stop), + ok. Modified: incubator/thrift/trunk/lib/erl/src/thrift_server.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_server.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_server.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_server.erl Mon Aug 30 22:05:00 2010 @@ -126,7 +126,7 @@ handle_info({inet_async, ListenSocket, R {stop, Reason, State} end; -handle_info({inet_async, _ListenSocket, _Ref, Error}, State) -> +handle_info({inet_async, ListenSocket, Ref, Error}, State) -> error_logger:error_msg("Error in acceptor: ~p~n", [Error]), {stop, Error, State}; @@ -177,7 +177,7 @@ start_processor(Socket, Service, Handler {ok, SocketTransport} = thrift_socket_transport:new(Socket), {ok, BufferedTransport} = thrift_buffered_transport:new(SocketTransport), {ok, Protocol} = thrift_binary_protocol:new(BufferedTransport), - {ok, Protocol} + {ok, Protocol, Protocol} end, spawn(thrift_processor, init, [{Server, ProtoGen, Service, Handler}]). Modified: incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_socket_server.erl Mon Aug 30 22:05:00 2010 @@ -166,12 +166,13 @@ gen_tcp_listen(Port, Opts, State) -> new_acceptor(State=#thrift_socket_server{max=0}) -> error_logger:error_msg("Not accepting new connections"), State#thrift_socket_server{acceptor=null}; -new_acceptor(State=#thrift_socket_server{listen=Listen, +new_acceptor(State=#thrift_socket_server{acceptor=OldPid, listen=Listen, service=Service, handler=Handler, socket_opts=Opts, framed=Framed }) -> Pid = proc_lib:spawn_link(?MODULE, acceptor_loop, [{self(), Listen, Service, Handler, Opts, Framed}]), +%% error_logger:info_msg("Spawning new acceptor: ~p => ~p", [OldPid, Pid]), State#thrift_socket_server{acceptor=Pid}. acceptor_loop({Server, Listen, Service, Handler, SocketOpts, Framed}) @@ -187,7 +188,7 @@ acceptor_loop({Server, Listen, Service, false -> thrift_buffered_transport:new(SocketTransport) end, {ok, Protocol} = thrift_binary_protocol:new(Transport), - {ok, Protocol} + {ok, IProt=Protocol, OProt=Protocol} end, thrift_processor:init({Server, ProtoGen, Service, Handler}); {error, closed} -> Modified: incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_socket_transport.erl Mon Aug 30 22:05:00 2010 @@ -29,8 +29,6 @@ -record(data, {socket, recv_timeout=infinity}). --type state() :: #data{}. --include("thrift_transport_behaviour.hrl"). new(Socket) -> new(Socket, []). @@ -47,26 +45,25 @@ new(Socket, Opts) when is_list(Opts) -> thrift_transport:new(?MODULE, State). %% Data :: iolist() -write(This = #data{socket = Socket}, Data) -> - {This, gen_tcp:send(Socket, Data)}. +write(#data{socket = Socket}, Data) -> + gen_tcp:send(Socket, Data). -read(This = #data{socket=Socket, recv_timeout=Timeout}, Len) +read(#data{socket=Socket, recv_timeout=Timeout}, Len) when is_integer(Len), Len >= 0 -> case gen_tcp:recv(Socket, Len, Timeout) of Err = {error, timeout} -> error_logger:info_msg("read timeout: peer conn ~p", [inet:peername(Socket)]), gen_tcp:close(Socket), - {This, Err}; - Data -> - {This, Data} + Err; + Data -> Data end. %% We can't really flush - everything is flushed when we write -flush(This) -> - {This, ok}. +flush(_) -> + ok. -close(This = #data{socket = Socket}) -> - {This, gen_tcp:close(Socket)}. +close(#data{socket = Socket}) -> + gen_tcp:close(Socket). %%%% FACTORY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Modified: incubator/thrift/trunk/lib/erl/src/thrift_transport.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_transport.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/lib/erl/src/thrift_transport.erl (original) +++ incubator/thrift/trunk/lib/erl/src/thrift_transport.erl Mon Aug 30 22:05:00 2010 @@ -37,42 +37,21 @@ behaviour_info(callbacks) -> -record(transport, {module, data}). --ifdef(transport_wrapper_module). --define(debug_wrap(Transport), - case Transport#transport.module of - ?transport_wrapper_module -> - Transport; - _Else -> - {ok, Result} = ?transport_wrapper_module:new(Transport), - Result - end). --else. --define(debug_wrap(Transport), Transport). --endif. - new(Module, Data) when is_atom(Module) -> - Transport0 = #transport{module = Module, data = Data}, - Transport1 = ?debug_wrap(Transport0), - {ok, Transport1}. + {ok, #transport{module = Module, + data = Data}}. --spec write(#transport{}, iolist() | binary()) -> {#transport{}, ok | {error, _Reason}}. +%% Data :: iolist() write(Transport, Data) -> Module = Transport#transport.module, - {NewTransData, Result} = Module:write(Transport#transport.data, Data), - {Transport#transport{data = NewTransData}, Result}. + Module:write(Transport#transport.data, Data). --spec read(#transport{}, non_neg_integer()) -> {#transport{}, {ok, binary()} | {error, _Reason}}. read(Transport, Len) when is_integer(Len) -> Module = Transport#transport.module, - {NewTransData, Result} = Module:read(Transport#transport.data, Len), - {Transport#transport{data = NewTransData}, Result}. + Module:read(Transport#transport.data, Len). + +flush(#transport{module = Module, data = Data}) -> + Module:flush(Data). --spec flush(#transport{}) -> {#transport{}, ok | {error, _Reason}}. -flush(Transport = #transport{module = Module, data = Data}) -> - {NewTransData, Result} = Module:flush(Data), - {Transport#transport{data = NewTransData}, Result}. - --spec close(#transport{}) -> {#transport{}, ok | {error, _Reason}}. -close(Transport = #transport{module = Module, data = Data}) -> - {NewTransData, Result} = Module:close(Data), - {Transport#transport{data = NewTransData}, Result}. +close(#transport{module = Module, data = Data}) -> + Module:close(Data). Modified: incubator/thrift/trunk/test/erl/Makefile URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/Makefile?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/test/erl/Makefile (original) +++ incubator/thrift/trunk/test/erl/Makefile Mon Aug 30 22:05:00 2010 @@ -29,7 +29,7 @@ SRCDIR=src ALL_INCLUDEDIR=$(GEN_INCLUDEDIR) $(INCLUDEDIR) ../../lib/erl/include INCLUDEFLAGS=$(patsubst %,-I%, ${ALL_INCLUDEDIR}) -MODULES = stress_server test_server test_client test_disklog test_membuffer +MODULES = stress_server test_server test_disklog test_membuffer test_tether INCLUDES = TARGETS = $(patsubst %,${TARGETDIR}/%.beam,${MODULES}) @@ -55,11 +55,11 @@ ${GENDIR}/: ${RPCFILE} ${GEN_TARGETDIR}/: ${GENDIR}/ rm -rf ${GEN_TARGETDIR} mkdir -p ${GEN_TARGETDIR} - erlc ${ERLC_FLAGS} ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl + erlc ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl $(TARGETS): ${TARGETDIR}/%.beam: ${SRCDIR}/%.erl ${GEN_INCLUDEDIR}/ ${HEADERS} mkdir -p ${TARGETDIR} - erlc ${ERLC_FLAGS} ${INCLUDEFLAGS} -o ${TARGETDIR} $< + erlc ${INCLUDEFLAGS} -o ${TARGETDIR} $< clean: rm -f ${TARGETDIR}/*.beam Modified: incubator/thrift/trunk/test/erl/src/test_disklog.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_disklog.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/test/erl/src/test_disklog.erl (original) +++ incubator/thrift/trunk/test/erl/src/test_disklog.erl Mon Aug 30 22:05:00 2010 @@ -29,21 +29,20 @@ t() -> {size, {1024*1024, 10}}]), {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory( TransportFactory, []), - {ok, Proto} = ProtocolFactory(), - {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift), + {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift), io:format("Client started~n"), % We have to make oneway calls into this client only since otherwise it will try % to read from the disklog and go boom. - {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]), + {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]), io:format("Call written~n"), % Use the send_call method to write a non-oneway call into the log - {Client2, ok} = thrift_client:send_call(Client1, testString, [<<"hello world">>]), + ok = thrift_client:send_call(Client, testString, [<<"hello world">>]), io:format("Non-oneway call sent~n"), - {_Client3, ok} = thrift_client:close(Client2), + ok = thrift_client:close(Client), io:format("Client closed~n"), ok. @@ -62,22 +61,21 @@ t_base64() -> thrift_buffered_transport:new_transport_factory(B64Factory), {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory( BufFactory, []), - {ok, Proto} = ProtocolFactory(), - {ok, Client0} = thrift_client:new(Proto, thriftTest_thrift), + {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift), io:format("Client started~n"), % We have to make oneway calls into this client only since otherwise it will try % to read from the disklog and go boom. - {Client1, {ok, ok}} = thrift_client:call(Client0, testOneway, [16#deadbeef]), + {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]), io:format("Call written~n"), % Use the send_call method to write a non-oneway call into the log - {Client2, ok} = thrift_client:send_call(Client1, testString, [<<"hello world">>]), + ok = thrift_client:send_call(Client, testString, [<<"hello world">>]), io:format("Non-oneway call sent~n"), - {_Client3, ok} = thrift_client:close(Client2), + ok = thrift_client:close(Client), io:format("Client closed~n"), ok. - + Modified: incubator/thrift/trunk/test/erl/src/test_membuffer.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_membuffer.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/test/erl/src/test_membuffer.erl (original) +++ incubator/thrift/trunk/test/erl/src/test_membuffer.erl Mon Aug 30 22:05:00 2010 @@ -30,12 +30,12 @@ test_data() -> t1() -> {ok, Transport} = thrift_memory_buffer:new(), - {ok, Protocol0} = thrift_binary_protocol:new(Transport), + {ok, Protocol} = thrift_binary_protocol:new(Transport), TestData = test_data(), - {Protocol1, ok} = thrift_protocol:write(Protocol0, + ok = thrift_protocol:write(Protocol, {{struct, element(2, thriftTest_types:struct_info('xtruct'))}, TestData}), - {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1, + {ok, Result} = thrift_protocol:read(Protocol, {struct, element(2, thriftTest_types:struct_info('xtruct'))}, 'xtruct'), @@ -44,12 +44,12 @@ t1() -> t2() -> {ok, Transport} = thrift_memory_buffer:new(), - {ok, Protocol0} = thrift_binary_protocol:new(Transport), + {ok, Protocol} = thrift_binary_protocol:new(Transport), TestData = test_data(), - {Protocol1, ok} = thrift_protocol:write(Protocol0, + ok = thrift_protocol:write(Protocol, {{struct, element(2, thriftTest_types:struct_info('xtruct'))}, TestData}), - {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1, + {ok, Result} = thrift_protocol:read(Protocol, {struct, element(2, thriftTest_types:struct_info('xtruct3'))}, 'xtruct3'), @@ -61,12 +61,12 @@ t2() -> t3() -> {ok, Transport} = thrift_memory_buffer:new(), - {ok, Protocol0} = thrift_binary_protocol:new(Transport), + {ok, Protocol} = thrift_binary_protocol:new(Transport), TestData = #bools{im_true = true, im_false = false}, - {Protocol1, ok} = thrift_protocol:write(Protocol0, + ok = thrift_protocol:write(Protocol, {{struct, element(2, thriftTest_types:struct_info('bools'))}, TestData}), - {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1, + {ok, Result} = thrift_protocol:read(Protocol, {struct, element(2, thriftTest_types:struct_info('bools'))}, 'bools'), @@ -74,23 +74,8 @@ t3() -> true = TestData#bools.im_false =:= Result#bools.im_false. -t4() -> - {ok, Transport} = thrift_memory_buffer:new(), - {ok, Protocol0} = thrift_binary_protocol:new(Transport), - TestData = #insanity{xtructs=[]}, - {Protocol1, ok} = thrift_protocol:write(Protocol0, - {{struct, element(2, thriftTest_types:struct_info('insanity'))}, - TestData}), - {_Protocol2, {ok, Result}} = thrift_protocol:read(Protocol1, - {struct, element(2, thriftTest_types:struct_info('insanity'))}, - 'insanity'), - - TestData = Result. - - t() -> t1(), t2(), - t3(), - t4(). + t3(). Modified: incubator/thrift/trunk/test/erl/src/test_server.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_server.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/test/erl/src/test_server.erl (original) +++ incubator/thrift/trunk/test/erl/src/test_server.erl Mon Aug 30 22:05:00 2010 @@ -19,42 +19,12 @@ -module(test_server). --export([go/0, go/1, start_link/2, handle_function/2]). +-export([start_link/1, handle_function/2]). -include("thriftTest_types.hrl"). --record(options, {port = 9090, - server_opts = []}). - -parse_args(Args) -> parse_args(Args, #options{}). -parse_args([], Opts) -> Opts; -parse_args([Head | Rest], Opts) -> - NewOpts = - case catch list_to_integer(Head) of - Port when is_integer(Port) -> - Opts#options{port = Port}; - _Else -> - case Head of - "framed" -> - Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]}; - "" -> - Opts; - _Else -> - erlang:error({bad_arg, Head}) - end - end, - parse_args(Rest, NewOpts). - -go() -> go([]). -go(Args) -> - #options{port = Port, server_opts = ServerOpts} = parse_args(Args), - spawn(fun() -> start_link(Port, ServerOpts), receive after infinity -> ok end end). - -start_link(Port, ServerOpts) -> - thrift_socket_server:start([{handler, ?MODULE}, - {service, thriftTest_thrift}, - {port, Port}] ++ - ServerOpts). +start_link(Port) -> + thrift_server:start_link(Port, thriftTest_thrift, ?MODULE). handle_function(testVoid, {}) -> @@ -154,12 +124,12 @@ handle_function(testInsanity, {Insanity} {?thriftTest_THREE, Crazy}]), SecondMap = dict:from_list([{?thriftTest_SIX, Looney}]), - + Insane = dict:from_list([{1, FirstMap}, {2, SecondMap}]), - + io:format("Return = ~p~n", [Insane]), - + {reply, Insane}; handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5}) @@ -180,7 +150,7 @@ handle_function(testException, {String}) case String of <<"Xception">> -> throw(#xception{errorCode = 1001, - message = String}); + message = <<"This is an Xception">>}); _ -> ok end; Added: incubator/thrift/trunk/test/erl/src/test_tether.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_tether.erl?rev=990957&view=auto ============================================================================== --- incubator/thrift/trunk/test/erl/src/test_tether.erl (added) +++ incubator/thrift/trunk/test/erl/src/test_tether.erl Mon Aug 30 22:05:00 2010 @@ -0,0 +1,186 @@ +%% +%% Licensed to the Apache Software Foundation (ASF) under one +%% or more contributor license agreements. See the NOTICE file +%% distributed with this work for additional information +%% regarding copyright ownership. The ASF licenses this file +%% to you under the Apache License, Version 2.0 (the +%% "License"); you may not use this file except in compliance +%% with the License. You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, +%% software distributed under the License is distributed on an +%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%% KIND, either express or implied. See the License for the +%% specific language governing permissions and limitations +%% under the License. +%% +%% Tests the behavior of clients in the face of transport errors. +%% Makes sure start, start_linked, and start_tethered work as expected. + +-module(test_tether). + +-compile(export_all). + + +t() -> + io:format("Beginning transport error test.~n"), + Pid1 = erlang:spawn(?MODULE, t_sub, [2]), + wait_for(Pid1), + io:format("Beginning protocol error test.~n"), + Pid2 = erlang:spawn(?MODULE, t_sub, [22]), + wait_for(Pid2), + ok. + +t_sub(Port) -> + io:format("Starting.~n", []), + register(tester, self()), + + Pid1 = erlang:spawn(?MODULE, test_start, [Port]), + receive after 200 -> ok end, % Wait for completion. + case is_up(Pid1) of + true -> + io:format("PASS. Unlinked owner still alive.~n"); + false -> + io:format("FAIL. Unlinked owner is dead.~n") + end, + + Pid2 = erlang:spawn(?MODULE, test_linked, [Port]), + receive after 200 -> ok end, % Wait for completion. + case is_up(Pid2) of + true -> + io:format("FAIL. Linked owner still alive.~n"); + false -> + io:format("PASS. Linked owner is dead.~n") + end, + + Pid3 = erlang:spawn(?MODULE, test_tethered, [Port]), + receive after 200 -> ok end, % Wait for completion. + case is_up(Pid3) of + true -> + io:format("PASS. Tethered owner still alive.~n"); + false -> + io:format("FAIL. Tethered owner is dead.~n") + end, + + check_extras(3). + +is_up(Pid) -> + MonitorRef = erlang:monitor(process, Pid), + receive + {'DOWN', MonitorRef, process, Pid, _Info} -> + false + after + 50 -> + erlang:demonitor(MonitorRef), + true + end. + +wait_for(Pid) -> + MonitorRef = erlang:monitor(process, Pid), + receive + {'DOWN', MonitorRef, process, Pid, _Info} -> + ok + end. + +check_extras(0) -> ok; +check_extras(N) -> + receive + {client, Type, Pid} -> + case {Type, is_up(Pid)} of + {unlinked, true} -> + io:format("PASS. Unlinked client still alive.~n"); + {unlinked, false} -> + io:format("FAIL. Unlinked client dead.~n"); + {linked, true} -> + io:format("FAIL. Linked client still alive.~n"); + {linked, false} -> + io:format("PASS. Linked client dead.~n"); + {tethered, true} -> + io:format("FAIL. Tethered client still alive.~n"); + {tethered, false} -> + io:format("PASS. Tethered client dead.~n") + end, + check_extras(N-1) + after + 500 -> + io:format("FAIL. Expected ~p more clients.~n", [N]) + end. + +make_thrift_client(Opts) -> + thrift_client:start(fun()->ok end, thriftTest_thrift, Opts). + +make_protocol_factory(Port) -> + {ok, TransportFactory} = + thrift_socket_transport:new_transport_factory( + "127.0.0.1", Port, []), + {ok, ProtocolFactory} = + thrift_binary_protocol:new_protocol_factory( + TransportFactory, []), + ProtocolFactory. + + +test_start(Port) -> + {ok, Client1} = make_thrift_client([{connect, false}]), + tester ! {client, unlinked, Client1}, + {ok, Client2} = make_thrift_client([{connect, false}]), + io:format("PASS. Unlinked clients created.~n"), + try + gen_server:call(Client2, {connect, make_protocol_factory(Port)}), + thrift_client:call(Client2, testVoid, []), + io:format("FAIL. Unlinked client connected and called.~n", []) + catch + Kind:Info -> + io:format("PASS. Caught unlinked error. ~p:~p~n", [Kind, Info]) + end, + receive after 100 -> + io:format("PASS. Still alive after unlinked death.~n"), + %% Hang around a little longer so our parent can verify. + receive after 200 -> ok end + end, + %% Exit abnormally to not kill our unlinked extra client. + exit(die). + +test_linked(Port) -> + {ok, Client1} = make_thrift_client([{connect, false}, {monitor, link}]), + tester ! {client, linked, Client1}, + {ok, Client2} = make_thrift_client([{connect, false}, {monitor, link}]), + io:format("PASS. Linked clients created.~n"), + try + gen_server:call(Client2, {connect, make_protocol_factory(Port)}), + thrift_client:call(Client2, testVoid, []), + io:format("FAIL. Linked client connected and called.~n", []) + catch + Kind:Info -> + io:format("FAIL. Caught linked error. ~p:~p~n", [Kind, Info]) + end, + receive after 100 -> + io:format("FAIL. Still alive after linked death.~n"), + % Hang around a little longer so our parent can verify. + receive after 200 -> ok end + end, + %% Exit abnormally to kill our linked extra client. + %% But we should never get here. + exit(die). + +test_tethered(Port) -> + {ok, Client1} = make_thrift_client([{connect, false}, {monitor, tether}]), + tester ! {client, tethered, Client1}, + {ok, Client2} = make_thrift_client([{connect, false}, {monitor, tether}]), + io:format("PASS. Tethered clients created.~n"), + try + gen_server:call(Client2, {connect, make_protocol_factory(Port)}), + thrift_client:call(Client2, testVoid, []), + io:format("FAIL. Tethered client connected and called.~n", []) + catch + Kind:Info -> + io:format("PASS. Caught tethered error. ~p:~p~n", [Kind, Info]) + end, + receive after 100 -> + io:format("PASS. Still alive after tethered death.~n"), + % Hang around a little longer so our parent can verify. + receive after 200 -> ok end + end, + %% Exit abnormally to kill our tethered extra client. + exit(die). Modified: incubator/thrift/trunk/tutorial/erl/client.erl URL: http://svn.apache.org/viewvc/incubator/thrift/trunk/tutorial/erl/client.erl?rev=990957&r1=990956&r2=990957&view=diff ============================================================================== --- incubator/thrift/trunk/tutorial/erl/client.erl (original) +++ incubator/thrift/trunk/tutorial/erl/client.erl Mon Aug 30 22:05:00 2010 @@ -29,50 +29,46 @@ p(X) -> t() -> Port = 9999, + + {ok, Client} = thrift_client:start_link("127.0.0.1", + Port, + calculator_thrift), - {ok, Client0} = thrift_client_util:new("127.0.0.1", - Port, - calculator_thrift, - []), - - {Client1, {ok, ok}} = thrift_client:call(Client0, ping, []), + thrift_client:call(Client, ping, []), io:format("ping~n", []), - {Client2, {ok, Sum}} = thrift_client:call(Client1, add, [1, 1]), + {ok, Sum} = thrift_client:call(Client, add, [1, 1]), io:format("1+1=~p~n", [Sum]), - {Client3, {ok, Sum1}} = thrift_client:call(Client2, add, [1, 4]), + {ok, Sum1} = thrift_client:call(Client, add, [1, 4]), io:format("1+4=~p~n", [Sum1]), Work = #work{op=?tutorial_SUBTRACT, num1=15, num2=10}, - {Client4, {ok, Diff}} = thrift_client:call(Client3, calculate, [1, Work]), + {ok, Diff} = thrift_client:call(Client, calculate, [1, Work]), io:format("15-10=~p~n", [Diff]), - {Client5, {ok, Log}} = thrift_client:call(Client4, getStruct, [1]), + {ok, Log} = thrift_client:call(Client, getStruct, [1]), io:format("Log: ~p~n", [Log]), - Client6 = - try - Work1 = #work{op=?tutorial_DIVIDE, - num1=1, - num2=0}, - {ClientS1, {ok, _Quot}} = thrift_client:call(Client5, calculate, [2, Work1]), - - io:format("LAME: exception handling is broken~n", []), - ClientS1 - catch - throw:{ClientS2, Z} -> - io:format("Got exception where expecting - the " ++ - "following is NOT a problem!!!~n"), - p(Z), - ClientS2 - end, + try + Work1 = #work{op=?tutorial_DIVIDE, + num1=1, + num2=0}, + {ok, _Quot} = thrift_client:call(Client, calculate, [2, Work1]), + + io:format("LAME: exception handling is broken~n", []) + catch + Z -> + io:format("Got exception where expecting - the " ++ + "following is NOT a problem!!!~n"), + p(Z) + end, - {Client7, {ok, ok}} = thrift_client:call(Client6, zip, []), + {ok, ok} = thrift_client:call(Client, zip, []), io:format("zip~n", []), - {_Client8, ok} = thrift_client:close(Client7), + ok = thrift_client:close(Client), ok.
