summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2008-12-22 20:35:50 +0000
committerDamien F. Katz <damien@apache.org>2008-12-22 20:35:50 +0000
commitc823bd2e8b3990b5c55dde54705d6866ad1eda4f (patch)
tree4be1ffa83f983e36038841f8b25812f2cfe6d482
parent112e286f3c0727caf6f6c96caa2ba40f31552ac7 (diff)
Fix for leaked file handles when not explicitly closed, added file stats code for checking for leaked file handles, and some refactoring of the view api.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@728764 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/couchdb/couch_db.erl2
-rw-r--r--src/couchdb/couch_db_updater.erl2
-rw-r--r--src/couchdb/couch_file.erl13
-rw-r--r--src/couchdb/couch_httpd_view.erl19
-rw-r--r--src/couchdb/couch_server.erl3
-rw-r--r--src/couchdb/couch_server_sup.erl6
-rw-r--r--src/couchdb/couch_view.erl62
7 files changed, 61 insertions, 46 deletions
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index 6684156f..0e652b68 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -463,7 +463,7 @@ init({DbName, Filepath, Fd, Options}) ->
gen_server:call(UpdaterPid, get_db).
terminate(_Reason, Db) ->
- exit(Db#db.update_pid, kill).
+ ok.
handle_call({open_ref_counted_instance, OpenerPid}, _From, #db{fd=Fd}=Db) ->
ok = couch_file:add_ref(Fd, OpenerPid),
diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl
index 68c3a1fc..b4faefee 100644
--- a/src/couchdb/couch_db_updater.erl
+++ b/src/couchdb/couch_db_updater.erl
@@ -179,9 +179,9 @@ handle_cast({compact_done, CompactFilepath}, #db{filepath=Filepath}=Db) ->
?LOG_INFO("Compaction file still behind main file "
"(update seq=~p. compact update seq=~p). Retrying.",
[Db#db.update_seq, NewSeq]),
+ couch_file:close(NewFd),
Pid = spawn_link(fun() -> start_copy_compact(Db) end),
Db2 = Db#db{compactor_pid=Pid},
- couch_file:close(NewFd),
{noreply, Db2}
end.
diff --git a/src/couchdb/couch_file.erl b/src/couchdb/couch_file.erl
index 06156324..9e60eb09 100644
--- a/src/couchdb/couch_file.erl
+++ b/src/couchdb/couch_file.erl
@@ -36,6 +36,7 @@ open(Filepath, Options) ->
case gen_server:start_link(couch_file,
{Filepath, Options, self(), Ref = make_ref()}, []) of
{ok, Fd} ->
+ couch_file_stats:track_file(Fd),
{ok, Fd};
ignore ->
% get the error
@@ -164,7 +165,9 @@ sync(Fd) ->
%% Returns: ok
%%----------------------------------------------------------------------
close(Fd) ->
- gen_server:cast(Fd, close).
+ Result = gen_server:cast(Fd, close),
+ catch unlink(Fd),
+ Result.
close_maybe(Fd) ->
gen_server:cast(Fd, {close_maybe, self()}).
@@ -185,6 +188,7 @@ add_ref(Fd, Pid) ->
num_refs(Fd) ->
gen_server:call(Fd, num_refs).
+
write_header(Fd, Prefix, Data) ->
TermBin = term_to_binary(Data),
% the size of all the bytes written to the header, including the md5 signature (16 bytes)
@@ -286,6 +290,7 @@ init_status_error(ReturnPid, Ref, Error) ->
% server functions
init({Filepath, Options, ReturnPid, Ref}) ->
+ process_flag(trap_exit, true),
case lists:member(create, Options) of
true ->
filelib:ensure_dir(Filepath),
@@ -325,8 +330,7 @@ init({Filepath, Options, ReturnPid, Ref}) ->
end.
-terminate(_Reason, Fd) ->
- file:close(Fd),
+terminate(_Reason, _Fd) ->
ok.
@@ -366,7 +370,6 @@ handle_call(num_refs, _From, Fd) ->
{reply, length(Monitors), Fd}.
-
handle_cast(close, Fd) ->
{stop,normal,Fd};
handle_cast({close_maybe, Pid}, Fd) ->
@@ -388,6 +391,8 @@ handle_cast({drop_ref, Pid}, Fd) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
+handle_info({'EXIT', _Pid, Reason}, Fd) ->
+ {stop, Reason, Fd};
handle_info({'DOWN', MonitorRef, _Type, Pid, _Info}, Fd) ->
{MonitorRef, _RefCount} = erase(Pid),
maybe_close_async(Fd).
diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl
index 13842149..35203ced 100644
--- a/src/couchdb/couch_httpd_view.erl
+++ b/src/couchdb/couch_httpd_view.erl
@@ -26,21 +26,20 @@ design_doc_view(Req, Db, Id, ViewName, Keys) ->
update = Update,
reduce = Reduce
} = QueryArgs = parse_view_query(Req, Keys),
- case couch_view:get_map_view({couch_db:name(Db),
- <<"_design/", Id/binary>>, ViewName, Update}) of
+ DesignId = <<"_design/", Id/binary>>,
+ case couch_view:get_map_view(Db, DesignId, ViewName, Update) of
{ok, View} ->
output_map_view(Req, View, Db, QueryArgs, Keys);
{not_found, Reason} ->
- case couch_view:get_reduce_view({couch_db:name(Db),
- <<"_design/", Id/binary>>, ViewName}) of
- {ok, View} ->
+ case couch_view:get_reduce_view(Db, DesignId, ViewName, Update) of
+ {ok, ReduceView} ->
parse_view_query(Req, Keys, true), % just for validation
case Reduce of
false ->
- {reduce, _N, _Lang, MapView} = View,
+ MapView = couch_view:extract_map_view(ReduceView),
output_map_view(Req, MapView, Db, QueryArgs, Keys);
_ ->
- output_reduce_view(Req, View, QueryArgs, Keys)
+ output_reduce_view(Req, ReduceView, QueryArgs, Keys)
end;
_ ->
throw({not_found, Reason})
@@ -72,11 +71,11 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
Keys = proplists:get_value(<<"keys">>, Props, nil),
case proplists:get_value(<<"reduce">>, Props, null) of
null ->
- {ok, View} = couch_view:get_map_view({temp, couch_db:name(Db), Language, MapSrc}),
+ {ok, View} = couch_view:get_temp_map_view(Db, Language, MapSrc),
output_map_view(Req, View, Db, QueryArgs, Keys);
RedSrc ->
- {ok, View} = couch_view:get_reduce_view(
- {temp, couch_db:name(Db), Language, MapSrc, RedSrc}),
+ {ok, View} = couch_view:get_temp_reduce_view(Db, Language, MapSrc,
+ RedSrc),
output_reduce_view(Req, View, QueryArgs, Keys)
end;
diff --git a/src/couchdb/couch_server.erl b/src/couchdb/couch_server.erl
index 2a2f51e2..f0e85734 100644
--- a/src/couchdb/couch_server.erl
+++ b/src/couchdb/couch_server.erl
@@ -270,9 +270,8 @@ handle_call({create, DbName, Options}, _From, Server) ->
Error ->
{reply, Error, Server}
end;
-handle_call({delete, DbName, Options}, _From, Server) ->
+handle_call({delete, DbName, _Options}, _From, Server) ->
DbNameList = binary_to_list(DbName),
- _UserCtx = proplists:get_value(user_ctx, Options, nil),
case check_dbname(Server, DbNameList) of
ok ->
FullFilepath = get_full_filename(Server, DbNameList),
diff --git a/src/couchdb/couch_server_sup.erl b/src/couchdb/couch_server_sup.erl
index 9c74a1a3..f0157864 100644
--- a/src/couchdb/couch_server_sup.erl
+++ b/src/couchdb/couch_server_sup.erl
@@ -139,6 +139,12 @@ start_primary_services() ->
brutal_kill,
supervisor,
[couch_server]},
+ {couch_file_stats,
+ {couch_file_stats, start_link, []},
+ permanent,
+ brutal_kill,
+ supervisor,
+ [couch_file_stats]},
{couch_db_update_event,
{gen_event, start_link, [{local, couch_db_update}]},
permanent,
diff --git a/src/couchdb/couch_view.erl b/src/couchdb/couch_view.erl
index 84f327e3..665cb6f7 100644
--- a/src/couchdb/couch_view.erl
+++ b/src/couchdb/couch_view.erl
@@ -13,9 +13,11 @@
-module(couch_view).
-behaviour(gen_server).
--export([start_link/0,fold/4,fold/5,less_json/2,less_json_keys/2,expand_dups/2,detuple_kvs/2]).
--export([init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,code_change/3]).
--export([get_reduce_view/1, get_map_view/1,get_row_count/1,reduce_to_count/1, fold_reduce/7]).
+-export([start_link/0,fold/4,fold/5,less_json/2,less_json_keys/2,expand_dups/2,
+ detuple_kvs/2,init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,
+ code_change/3,get_reduce_view/4,get_temp_reduce_view/4,get_temp_map_view/3,
+ get_map_view/4,get_row_count/1,reduce_to_count/1,fold_reduce/7,
+ extract_map_view/1]).
-include("couch_db.hrl").
@@ -23,7 +25,8 @@ start_link() ->
gen_server:start_link({local, couch_view}, couch_view, [], []).
get_temp_updater(DbName, Type, MapSrc, RedSrc) ->
- {ok, Pid} = gen_server:call(couch_view, {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
+ {ok, Pid} = gen_server:call(couch_view,
+ {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
Pid.
get_group_server(DbName, GroupId) ->
@@ -34,21 +37,28 @@ get_group_server(DbName, GroupId) ->
throw(Error)
end.
-get_updated_group(DbName, GroupId, Update) ->
- couch_view_group:request_group(get_group_server(DbName, GroupId), seq_for_update(DbName, Update)).
+get_group(Db, GroupId, Update) ->
+ couch_view_group:request_group(
+ get_group_server(couch_db:name(Db), GroupId),
+ if Update -> couch_db:get_update_seq(Db); true -> 0 end).
-get_updated_group(temp, DbName, Type, MapSrc, RedSrc, Update) ->
- couch_view_group:request_group(get_temp_updater(DbName, Type, MapSrc, RedSrc), seq_for_update(DbName, Update)).
+
+get_temp_group(Db, Type, MapSrc, RedSrc) ->
+ couch_view_group:request_group(
+ get_temp_updater(couch_db:name(Db), Type, MapSrc, RedSrc),
+ couch_db:get_update_seq(Db)).
get_row_count(#view{btree=Bt}) ->
{ok, {Count, _Reds}} = couch_btree:full_reduce(Bt),
{ok, Count}.
-get_reduce_view({temp, DbName, Type, MapSrc, RedSrc}) ->
- {ok, #group{views=[View]}} = get_updated_group(temp, DbName, Type, MapSrc, RedSrc, true),
- {ok, {temp_reduce, View}};
-get_reduce_view({DbName, GroupId, Name}) ->
- case get_updated_group(DbName, GroupId, true) of
+get_temp_reduce_view(Db, Type, MapSrc, RedSrc) ->
+ {ok, #group{views=[View]}} = get_temp_group(Db, Type, MapSrc, RedSrc),
+ {ok, {temp_reduce, View}}.
+
+
+get_reduce_view(Db, GroupId, Name, Update) ->
+ case get_group(Db, GroupId, Update) of
{ok, #group{views=Views,def_lang=Lang}} ->
get_reduce_view0(Name, Lang, Views);
Error ->
@@ -63,6 +73,9 @@ get_reduce_view0(Name, Lang, [#view{reduce_funs=RedFuns}=View|Rest]) ->
N -> {ok, {reduce, N, Lang, View}}
end.
+extract_map_view({reduce, _N, _Lang, View}) ->
+ View.
+
detuple_kvs([], Acc) ->
lists:reverse(Acc);
detuple_kvs([KV | Rest], Acc) ->
@@ -113,21 +126,14 @@ get_key_pos(Key, [{Key1,_Value}|_], N) when Key == Key1 ->
N + 1;
get_key_pos(Key, [_|Rest], N) ->
get_key_pos(Key, Rest, N+1).
-
-seq_for_update(DbName, Update) ->
- case Update of
- true ->
- {ok, #db{update_seq=CurrentSeq}} = couch_db:open(DbName, []),
- CurrentSeq;
- _Else ->
- 0
- end.
-
-get_map_view({temp, DbName, Type, Src}) ->
- {ok, #group{views=[View]}} = get_updated_group(temp, DbName, Type, Src, [], true),
- {ok, View};
-get_map_view({DbName, GroupId, Name, Update}) ->
- case get_updated_group(DbName, GroupId, Update) of
+
+
+get_temp_map_view(Db, Type, Src) ->
+ {ok, #group{views=[View]}} = get_temp_group(Db, Type, Src, []),
+ {ok, View}.
+
+get_map_view(Db, GroupId, Name, Update) ->
+ case get_group(Db, GroupId, Update) of
{ok, #group{views=Views}} ->
get_map_view0(Name, Views);
Error ->