From: Christopher Piro Date: Tue, 2 Oct 2007 00:35:12 +0000 (+0000) Subject: [thrift] otpification and sane configuration for Erlang Thrift X-Git-Tag: 0.2.0~1188 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=68940295e1b2e8caca6376b95879ef252bc5dd3e;p=common%2Fthrift.git [thrift] otpification and sane configuration for Erlang Thrift Summary: a small victory in the neverending quest of OTPifying this binding -- search for config files in ./conf/ (relative to the cwd of the emulator). for example, when you start the channel server, ./conf/{channel,thrift}.conf should exist. better than having to recompile to change a configuration ... reconfig should take care of that in running code. Test Plan: works with channel server git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665284 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/erl/include/thrift.hrl b/lib/erl/include/thrift.hrl index 3be2f686..fdeaf1d8 100644 --- a/lib/erl/include/thrift.hrl +++ b/lib/erl/include/thrift.hrl @@ -1,105 +1,16 @@ %%% Copyright (c) 2007- Facebook %%% Distributed under the Thrift Software License -%%% +%%% %%% See accompanying file LICENSE or visit the Thrift site at: %%% http://developers.facebook.com/thrift/ +-define(CONFIG_FILE, filename:join("conf", "thrift.conf")). + -define(ERROR(F, D), error_logger:format(F, D)). + -define(INFO(Type, Report), error_logger:info_report({thrift_info, Type}, Report)). -% local (same process) --define(L0(Method), oop:call(This, Method, [])). --define(L1(Method, Arg1), oop:call(This, Method, [Arg1])). --define(L2(Method, Arg1, Arg2), oop:call(This, Method, [Arg1, Arg2])). --define(L3(Method, Arg1, Arg2, Arg3), oop:call(This, Method, [Arg1, Arg2, Arg3])). --define(L4(Method, Arg1, Arg2, Arg3, Arg4), oop:call(This, Method, [Arg1, Arg2, Arg3, Arg4])). --define(L5(Method, Arg1, Arg2, Arg3, Arg4, Arg5), oop:call(This, Method, [Arg1, Arg2, Arg3, Arg4, Arg5])). --define(L6(Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), oop:call(This, Method, [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6])). - -% local (same process), but not This (e.g. t*Factory) --define(F0(Obj, Method), oop:call(Obj, Method, [])). --define(F1(Obj, Method, Arg1), oop:call(Obj, Method, [Arg1])). --define(F2(Obj, Method, Arg1, Arg2), oop:call(Obj, Method, [Arg1, Arg2])). --define(F3(Obj, Method, Arg1, Arg2, Arg3), oop:call(Obj, Method, [Arg1, Arg2, Arg3])). --define(F4(Obj, Method, Arg1, Arg2, Arg3, Arg4), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4])). --define(F5(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4, Arg5])). --define(F6(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6])). - -% remote (different process) --define(RT0(ServerRef, Method, Timeout), gen_server:call(ServerRef, {Method, []}, Timeout)). --define(RT1(ServerRef, Method, Timeout, Arg1), gen_server:call(ServerRef, {Method, [Arg1]}, Timeout)). --define(RT2(ServerRef, Method, Timeout, Arg1, Arg2), gen_server:call(ServerRef, {Method, [Arg1, Arg2]}, Timeout)). --define(RT3(ServerRef, Method, Timeout, Arg1, Arg2, Arg3), gen_server:call(ServerRef, {Method, [Arg1, Arg2, Arg3]}, Timeout)). --define(RT4(ServerRef, Method, Timeout, Arg1, Arg2, Arg3, Arg4), gen_server:call(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4]}, Timeout)). --define(RT5(ServerRef, Method, Timeout, Arg1, Arg2, Arg3, Arg4, Arg5), gen_server:call(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4, Arg5]}, Timeout)). --define(RT6(ServerRef, Method, Timeout, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), gen_server:call(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6]}, Timeout)). - -% remote (different process), default timeout --define(DEFAULT_TIMEOUT, 5000). --define(R0(ServerRef, Method), ?RT0(ServerRef, Method, ?DEFAULT_TIMEOUT)). --define(R1(ServerRef, Method, Arg1), ?RT1(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1)). --define(R2(ServerRef, Method, Arg1, Arg2), ?RT2(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1, Arg2)). --define(R3(ServerRef, Method, Arg1, Arg2, Arg3), ?RT3(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1, Arg2, Arg3)). --define(R4(ServerRef, Method, Arg1, Arg2, Arg3, Arg4), ?RT4(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1, Arg2, Arg3, Arg4)). --define(R5(ServerRef, Method, Arg1, Arg2, Arg3, Arg4, Arg5), ?RT5(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1, Arg2, Arg3, Arg4, Arg5)). --define(R6(ServerRef, Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), ?RT6(ServerRef, Method, ?DEFAULT_TIMEOUT, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)). - -% remote (different process), cast --define(C0(ServerRef, Method), gen_server:cast(ServerRef, {Method, []})). --define(C1(ServerRef, Method, Arg1), gen_server:cast(ServerRef, {Method, [Arg1]})). --define(C2(ServerRef, Method, Arg1, Arg2), gen_server:cast(ServerRef, {Method, [Arg1, Arg2]})). --define(C3(ServerRef, Method, Arg1, Arg2, Arg3), gen_server:cast(ServerRef, {Method, [Arg1, Arg2, Arg3]})). --define(C4(ServerRef, Method, Arg1, Arg2, Arg3, Arg4), gen_server:cast(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4]})). --define(C5(ServerRef, Method, Arg1, Arg2, Arg3, Arg4, Arg5), gen_server:cast(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4, Arg5]})). --define(C6(ServerRef, Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), gen_server:cast(ServerRef, {Method, [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6]})). - -% spawn new server -%% -define(NEW(Class, Args), %% -%% gen_server:start_link(thrift_oop_server, {Class, Args}, [])). %% -%% moved to oop:start_new/2 - -% old -%% -define(M0(Obj, Method), oop:call(Obj, Method, [])). %% -%% -define(M1(Obj, Method, Arg1), oop:call(Obj, Method, [Arg1])). %% -%% -define(M2(Obj, Method, Arg1, Arg2), oop:call(Obj, Method, [Arg1, Arg2])). %% -%% -define(M3(Obj, Method, Arg1, Arg2, Arg3), oop:call(Obj, Method, [Arg1, Arg2, Arg3])). %% -%% -define(M4(Obj, Method, Arg1, Arg2, Arg3, Arg4), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4])). %% -%% -define(M5(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4, Arg5])). %% -%% -define(M6(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), oop:call(Obj, Method, [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6])). %% - -%%% implicit call: old - -%% -define(M0(Obj, Method), ((?CLASS(Obj)):Method(Obj))). %% -%% -define(M1(Obj, Method, Arg1), ((?CLASS(Obj)):Method(Obj, Arg1))). %% -%% -define(M2(Obj, Method, Arg1, Arg2), ((?CLASS(Obj)):Method(Obj, Arg1, Arg2))). %% -%% -define(M3(Obj, Method, Arg1, Arg2, Arg3), ((?CLASS(Obj)):Method(Obj, Arg1, Arg2, Arg3))). %% -%% -define(M4(Obj, Method, Arg1, Arg2, Arg3, Arg4), ((?CLASS(Obj)):Method(Obj, Arg1, Arg2, Arg3, Arg4))). %% -%% -define(M5(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5), ((?CLASS(Obj)):Method(Obj, Arg1, Arg2, Arg3, Arg4, Arg5))). %% -%% -define(M6(Obj, Method, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6), ((?CLASS(Obj)):Method(Obj, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6))). %% - -%% TType --define(tType_STOP, 0). --define(tType_VOID, 1). --define(tType_BOOL, 2). --define(tType_BYTE, 3). --define(tType_DOUBLE, 4). --define(tType_I16, 6). --define(tType_I32, 8). --define(tType_I64, 10). --define(tType_STRING, 11). --define(tType_STRUCT, 12). --define(tType_MAP, 13). --define(tType_SET, 14). --define(tType_LIST, 15). - -% tmessagetype --define(tMessageType_CALL, 1). --define(tMessageType_REPLY, 2). --define(tMessageType_EXCEPTION, 3). - -% TProcessor -% ? - -% -include("tApplicationException.hrl"). +-include("thrift_macros.hrl"). +-include("thrift_constants.hrl"). diff --git a/lib/erl/src/Makefile b/lib/erl/src/Makefile index 1a07b0a9..b42e0056 100644 --- a/lib/erl/src/Makefile +++ b/lib/erl/src/Makefile @@ -67,6 +67,7 @@ include ../build/docs.mk # beam files. clean: rm -f $(TARGET_FILES) + rm -f *~ rm -f core rm -rf $(EBIN) rm -rf *html diff --git a/lib/erl/src/oop.erl b/lib/erl/src/oop.erl index e3685eea..08c0e37d 100644 --- a/lib/erl/src/oop.erl +++ b/lib/erl/src/oop.erl @@ -63,7 +63,6 @@ set(Obj, Field, Value) -> %% TODO: could be tail-recursive ?NOATTR_SET end end. - %%% C++ <-> Erlang %%% classes modules diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src index dc2926a0..590e6a9b 100755 --- a/lib/erl/src/thrift.app.src +++ b/lib/erl/src/thrift.app.src @@ -35,7 +35,7 @@ {env, []}, % The Module and Args used to start this application. - {mod, {%APP_NAME%, []}} + {mod, {thrift_app, []}} ] }. diff --git a/lib/erl/src/thrift.erl b/lib/erl/src/thrift.erl index feabb1d1..5dc89876 100644 --- a/lib/erl/src/thrift.erl +++ b/lib/erl/src/thrift.erl @@ -1,13 +1,12 @@ %%% Copyright (c) 2007- Facebook %%% Distributed under the Thrift Software License -%%% +%%% %%% See accompanying file LICENSE or visit the Thrift site at: %%% http://developers.facebook.com/thrift/ -module(thrift). --export([start/2, shutdown/0, stop/1]). --behaviour(application). +-export([start/0, stop/0, config/1, config/2]). -include("thrift.hrl"). @@ -15,11 +14,56 @@ %%% behavior definition %%% -start(Type, StartArgs) -> - ok. +start() -> + application:start(thrift). + +stop() -> + application:stop(thrift). + +%%% +%%% configuration +%%% + +%% go to the global file by default +config(Path) -> + config(Path, {file, ?CONFIG_FILE}). + +config(Path, Source) -> + case config1(Path, Source) of + {error, file_error, R} -> + ?ERROR("error opening config ~p: ~p", [Source, R]), + false; + {error, bad_item, Tuple} -> + ?ERROR("malformed config item ~p found at ~p in ~p", [Tuple, Path, Source]), + false; + {error, not_found} -> + ?ERROR("config item ~p not found in ~p", [Path, Source]), + false; + {value, V} -> + {value, V} + end. -shutdown() -> - application:stop(?MODULE). +%% go to a file +config1(Path, {file, File}) -> + case file:consult(File) of + {error, R={_,_,_}} -> + {error, file_error, file:format_error(R)}; + {error, Posix} -> + {error, file_error, Posix}; + {ok, List} when is_list(List) -> + config1(Path, List) + end; -stop(_State) -> - ok. +%% go through a list from a file or a sublist +config1([P|Ps], List) when is_list(List) -> + case lists:keysearch(P, 1, List) of + {value, Tuple} when size(Tuple) == 2 -> + List1 = element(2, Tuple), %% either another list or, if Ps is [], the item itself + config1(Ps, List1); + {value, Tuple} -> + {error, bad_item, Tuple}; + false -> + {error, not_found} + end; +config1([], Item) -> {value, Item}; +config1(Item, Source) -> config1([Item], Source). diff --git a/lib/erl/src/thrift_logger.erl b/lib/erl/src/thrift_logger.erl index 12aa0596..6deb222b 100644 --- a/lib/erl/src/thrift_logger.erl +++ b/lib/erl/src/thrift_logger.erl @@ -8,7 +8,9 @@ -behaviour(gen_event). --include("thrift_logger.hrl"). +-record(state, {config}). + +-define(CONFIG(Item), config(Item, State)). %% TODO(cpiro): either %% make exceptions know whether they need to be displayed @@ -23,13 +25,14 @@ -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). --export([install/0, install/1]). +-export([install/0, install/1, reconfig/0, reconfig/1]). %% ensure the regular logger is out and ours is in install() -> install([]). -install(Args) -> +install(Config) -> %% remove loggers + io:format("starting logger~n"), lists:foreach(fun(Logger) -> case Logger of _ -> gen_event:delete_handler(error_logger, Logger, normal) @@ -38,15 +41,19 @@ install(Args) -> %% TODO(cpiro): sasl someday? %% gen_event:add_handler(error_logger, sasl_report_file_h, {LogFile, all}), - gen_event:add_handler(error_logger, ?MODULE, Args). -%% how to output -format(Format, Data) -> - io:format(Format, Data). + gen_event:add_handler(error_logger, ?MODULE, []), -%% convenience -sformat(Format, Data) -> - thrift_utils:sformat(Format, Data). + reconfig(Config), + + ok. + +%% load our config file and amend the given stuff +reconfig() -> + reconfig([]). + +reconfig(Config) -> + gen_event:call(error_logger, ?MODULE, {reconfig, Config}). %%==================================================================== %% gen_event callbacks @@ -60,15 +67,15 @@ sformat(Format, Data) -> %% @end %%-------------------------------------------------------------------- init([]) -> - {ok, #thrift_logger_state{ - term_width = 110, - force_one_line = true, - omit = [oop_new], % req_processed - gen_server_messages = false, - lookup = true - }}; - -init([State]) -> + BootConfig = [ + {term_width, 80}, + {force_one_line, false}, + {omit, []}, + {gen_server_messages, true}, + {lookup, false} + ], %% configuration before we try loading from file + + State = #state{config=BootConfig}, {ok, State}. %%-------------------------------------------------------------------- @@ -101,7 +108,7 @@ handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string end, Length = - case (length(OutputSafe) + BannerLen) < State#thrift_logger_state.term_width of + case (length(OutputSafe) + BannerLen) < ?CONFIG(term_width) of true -> short; false -> long end, @@ -112,7 +119,7 @@ handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string false -> multiline end, - case { State#thrift_logger_state.force_one_line, Length, OneLine } of + case { ?CONFIG(force_one_line), Length, OneLine } of %% one line and short ... print as is {_, short, oneliner} -> format("~s~s~n", [Banner, OutputSafe]); @@ -120,7 +127,7 @@ handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string %% too long ... squash to one {true, long, _} -> O = Banner ++ OutputSafe, - Format = sformat("~~~ps >~n", [State#thrift_logger_state.term_width-2]), % e.g. "~80s >~n" + Format = sformat("~~~ps >~n", [?CONFIG(term_width)-2]), % e.g. "~80s >~n" format(Format, [O]); %% short but multiline... collapse to one @@ -144,7 +151,7 @@ handle_event1({What, _Gleader, {Pid, Format, Data}}, State) when is_list(Format) case Format of "** Generic server ~p terminating \n** Last message in was ~p~n** When Server state == ~p~n** Reason for termination == ~n** ~p~n" -> %% v- Pid is a pattern match, not a bind - [Pid, LastMessage, Obj, Reason] = Data, + [Ref, LastMessage, Obj, Reason] = Data, %% TODO: move as much logic as possible out of thrift_logger Ignore = @@ -168,11 +175,11 @@ handle_event1({What, _Gleader, {Pid, Format, Data}}, State) when is_list(Format) false -> Format1 = "** gen_server terminating in message ~p~n** State = ~s~n** Reason = ~s~n", Message = sformat(Format1, [LastMessage, oop:inspect(Obj), oop:inspect(Reason)]), %% TODO(cpiro): hope Reason is an object? - handle_event2(Symbol, Pid, "", Message, State) + handle_event2(Symbol, Ref, "", Message, State) end; _ -> Message = sformat(Format, Data), - handle_event2(Symbol, Pid, "", Message, State) + handle_event2(Symbol, Ref, "", Message, State) end, {ok, State}; @@ -187,7 +194,7 @@ handle_event1({What, _Gleader, {Pid, Type, Report}}, State) -> case Type of {thrift_info, TI} -> %% should we show it? - case not lists:member(TI, State#thrift_logger_state.omit) of + case not lists:member(TI, ?CONFIG(omit)) of true -> Message = handle_thrift_info(TI, Report, State), handle_event2(Symbol, Pid, "", Message, State); @@ -249,7 +256,7 @@ handle_thrift_info(Else, Report, State) -> %%-------------------------------------------------------------------- %% @spec handle_call(Request, State) -> {ok, Reply, State} | -%% {swap_handler, Reply, Args1, State1, +%% {swap_handler, Reply, Args1, State1, %% Mod2, Args2} | %% {remove_handler, Reply}. %% @@ -259,6 +266,11 @@ handle_thrift_info(Else, Report, State) -> %% handler to handle the request. %% @end %%-------------------------------------------------------------------- +handle_call({reconfig, Amendments}, State) -> + {OkOrError, State1} = reconfig1(State, Amendments), + format(".. reconfig was ~p~n", [OkOrError]), + {ok, OkOrError, State1}; + handle_call(_Request, State) -> Reply = ok, {ok, Reply, State}. @@ -305,3 +317,32 @@ code_change(_OldVsn, State, _Extra) -> %%==================================================================== %%% Internal functions %%==================================================================== + +%% how to output +format(Format, Data) -> + io:format(Format, Data). + +%% convenience +sformat(Format, Data) -> + thrift_utils:sformat(Format, Data). + +reconfig1(State, Amendments) -> + case thrift:config(thrift_logger) of + {value, Config} -> + Config1 = lists:keysort(1, Config), + Amendments1 = lists:keysort(1, Amendments), + Config2 = lists:keymerge(1, Amendments1, Config1), + + State1 = State#state{config=Config2}, + {ok, State1}; + _ -> + {error, State} + end. + +config(Item, State) -> + case thrift:config(Item, State#state.config) of + {value, V} -> + V; + Else -> + ?ERROR("config for ~p is unavailable: ~p", [Item, Else]) + end. diff --git a/lib/erl/src/transport/tSocket.erl b/lib/erl/src/transport/tSocket.erl index 491d86b6..c2bf920d 100644 --- a/lib/erl/src/transport/tSocket.erl +++ b/lib/erl/src/transport/tSocket.erl @@ -17,8 +17,8 @@ -export([attr/4, super/0, inspect/1]). --export([new/0, new/1, new/2, - effectful_setHandle/2, effectful_open/1, +-export([new/0, new/1, new/2, + effectful_setHandle/2, effectful_open/1, isOpen/1, write/2, read/2, effectful_close/1]). %%% @@ -91,6 +91,9 @@ write(This, Str) -> Handle = oop:get(This, handle), Val = gen_tcp:send(Handle, Str), + %% DEBUG + %% error_logger:info_msg("tSocket: wrote ~p~n", [Str]), + %% error_logger:info_msg("WRITE |~p| (~p)", [Str,Val]), case Val of @@ -108,6 +111,8 @@ read(This, Sz) -> Port = oop:get(This, port), throw(tTransportException:new(?tTransportException_UNKNOWN, "TSocket: Could not read " ++ Sz ++ "bytes from " ++ Host ++ ":" ++ Port)); {ok, Data} -> + %% DEBUG + %% io:format("tSocket: read ~p~n", [Data]), Data; {error, Error} -> exit(tTransportException:new(?tTransportException_NOT_OPEN, "in tSocket:read/2: gen_tcp:recv"))