No title Revision 353336333637 (Wed Jul 13 2011 at 12:27) - Diff Link to this snippet: https://friendpaste.com/X9tX1LCb9Mn6SiTueFlXY Embed: manni perldoc borland colorful default murphy trac fruity autumn bw emacs pastie friendly Show line numbers Wrap lines 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116diff --git a/src/couchdb/couch_log.erl b/src/couchdb/couch_log.erlindex 2676689..03e2fa7 100644--- a/src/couchdb/couch_log.erl+++ b/src/couchdb/couch_log.erl@@ -27,10 +27,12 @@ -define(LEVEL_INFO, 2). -define(LEVEL_DEBUG, 1). +-define(MAX_BUFFER_LEN, 64 * 1024).+ -record(state, {- fd, level,- sasl+ sasl,+ writer }). debug(Format, Args) ->@@ -81,17 +83,21 @@ init([]) -> Sasl = couch_config:get("log", "include_sasl", "true") =:= "true", case ets:info(?MODULE) of- undefined -> ets:new(?MODULE, [named_table]);+ undefined -> ets:new(?MODULE, [named_table, {read_concurrency, true}]); _ -> ok end, ets:insert(?MODULE, {level, Level}), - case file:open(Filename, [append]) of- {ok, Fd} ->- {ok, #state{fd = Fd, level = Level, sasl = Sasl}};- {error, eacces} ->+ process_flag(trap_exit, true),+ Parent = self(),+ Writer = spawn_link(fun() -> writer(Parent, Filename) end),++ receive+ {Writer, ok} ->+ {ok, #state{writer = Writer, level = Level, sasl = Sasl}};+ {Writer, {error, eacces}} -> {stop, {file_permission_error, Filename}};- Error ->+ {Writer, Error} -> {stop, Error} end. @@ -143,18 +149,21 @@ handle_call({set_level_integer, NewLevel}, State) -> ets:insert(?MODULE, {level, NewLevel}), {ok, ok, State#state{level = NewLevel}}. +handle_info({'EXIT', Pid, Reason}, #state{writer = Pid}) ->+ io:format("[error] log writer died: ~p~n", [Reason]),+ exit({log_writer_died, Reason}); handle_info(_Info, State) -> {ok, State}. code_change(_OldVsn, State, _Extra) -> {ok, State}. -terminate(_Arg, #state{fd = Fd}) ->- file:close(Fd).+terminate(_Arg, #state{writer = Writer}) ->+ Writer ! stop,+ receive {'EXIT', Writer, _} -> ok end. -log(#state{fd = Fd}, ConsoleMsg, FileMsg) ->- ok = io:put_chars(ConsoleMsg),- ok = io:put_chars(Fd, FileMsg).+log(#state{writer = Writer}, ConsoleMsg, FileMsg) ->+ Writer ! {log, FileMsg, ConsoleMsg}. get_log_messages(Pid, Level, Format, Args) -> ConsoleMsg = unicode:characters_to_binary(io_lib:format(@@ -175,3 +184,41 @@ read(Bytes, Offset) -> {ok, Chunk} = file:pread(Fd, Start, LogFileSize), ok = file:close(Fd), Chunk.+++writer(Parent, Filename) ->+ case file:open(Filename, [append, raw, binary]) of+ {ok, Fd} ->+ Parent ! {self(), ok},+ writer_loop(Fd);+ Error ->+ Parent ! {self(), Error}+ end.++writer_loop(Fd) ->+ receive+ {log, FileMsg, ConsoleMsg} ->+ ok = io:put_chars(ConsoleMsg),+ ok = file:write(Fd, FileMsg),+ writer_loop(Fd);+ % writer_loop_batch(Fd, [FileMsg], [ConsoleMsg], byte_size(FileMsg));+ stop ->+ ok = file:close(Fd)+ end.++writer_loop_batch(Fd, AccFile, AccConsole, Len) when Len >= ?MAX_BUFFER_LEN ->+ ok = io:put_chars(lists:reverse(AccConsole)),+ ok = file:write(Fd, lists:reverse(AccFile)),+ writer_loop(Fd);++writer_loop_batch(Fd, AccFile, AccConsole, Len) ->+ receive+ {log, FileMsg, ConsoleMsg} ->+ writer_loop_batch(+ Fd, [FileMsg | AccFile], [ConsoleMsg | AccConsole],+ Len + byte_size(FileMsg))+ after 0 ->+ ok = io:put_chars(lists:reverse(AccConsole)),+ ok = file:write(Fd, lists:reverse(AccFile)),+ writer_loop(Fd)+ end.