summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2018-09-19 10:46:57 -0500
committerPaul J. Davis <paul.joseph.davis@gmail.com>2018-09-19 10:46:57 -0500
commit217bab9569b398710d40966c66db168f4b0ae5f9 (patch)
tree15230abfa558dbae94b7259bbac2041ac33c0bfe
parent04eed00269ca8979ba0245ca2a00977bdfee6905 (diff)
downloadcouchdb-217bab9569b398710d40966c66db168f4b0ae5f9.tar.gz
Move work from couch_server to open_async
This moves a lot of the mundane work out of couch_server's main loop and into the open_async process to minimize the number of reductions and messages required to handle individual messages arrivng in couch_server's mailbox. The three main bits of work are: getting the engine for the database, logging error results, and updating the open time histogram.
-rw-r--r--src/couch/src/couch_server.erl123
1 files changed, 63 insertions, 60 deletions
diff --git a/src/couch/src/couch_server.erl b/src/couch/src/couch_server.erl
index 65339fc66..8189f90af 100644
--- a/src/couch/src/couch_server.erl
+++ b/src/couch/src/couch_server.erl
@@ -413,24 +413,31 @@ close_lru_int(DbName) ->
end.
-open_async(Server, From, DbName, {Module, Filepath}, Options) ->
+open_async(Server, From, DbName, Options) ->
Parent = self(),
T0 = os:timestamp(),
Opener = spawn_link(fun() ->
- Res = couch_db:start_link(Module, DbName, Filepath, Options),
- case {Res, lists:member(create, Options)} of
- {{ok, _Db}, true} ->
+ Res = open_async_int(Server, DbName, Options),
+ IsSuccess = case Res of
+ {ok, _Db} -> true;
+ _ -> false
+ end,
+ case IsSuccess andalso lists:member(create, Options) of
+ true ->
couch_event:notify(DbName, created);
- _ ->
+ false ->
ok
end,
- gen_server:call(Parent, {open_result, T0, DbName, Res}, infinity),
+ gen_server:call(Parent, {open_result, DbName, Res}, infinity),
unlink(Parent),
- case Res of
- {ok, _} ->
- ok;
- Error ->
- couch_log:info("open_result error ~p for ~s", [Error, DbName])
+ case IsSuccess of
+ true ->
+ % Track latency times for successful opens
+ OpenTime = timer:now_diff(os:timestamp(), T0) / 1000,
+ couch_stats:update_histogram([couchdb, db_open_time], OpenTime);
+ false ->
+ % Log unsuccessful results
+ couch_log:info("open_result error ~p for ~s", [Res, DbName])
end
end),
ReqType = case lists:member(create, Options) of
@@ -448,6 +455,22 @@ open_async(Server, From, DbName, {Module, Filepath}, Options) ->
true = ets:insert(couch_dbs_pid_to_name, {Opener, DbName}),
db_opened(Server, Options).
+
+open_async_int(Server, DbName, Options) ->
+ DbNameList = binary_to_list(DbName),
+ case check_dbname(Server, DbNameList) of
+ ok ->
+ case get_engine(Server, DbNameList, Options) of
+ {ok, {Module, FilePath}} ->
+ couch_db:start_link(Module, DbName, FilePath, Options);
+ Error2 ->
+ Error2
+ end;
+ Error1 ->
+ Error1
+ end.
+
+
handle_call(close_lru, _From, #server{lru=Lru} = Server) ->
case close_lru(Lru) of
{true, NewLru} ->
@@ -465,10 +488,8 @@ handle_call(reload_engines, _From, Server) ->
{reply, ok, Server#server{engines = get_configured_engines()}};
handle_call(get_server, _From, Server) ->
{reply, {ok, Server}, Server};
-handle_call({open_result, T0, DbName, {ok, Db}}, {Opener, _}, Server) ->
+handle_call({open_result, DbName, {ok, Db}}, {Opener, _}, Server) ->
true = ets:delete(couch_dbs_pid_to_name, Opener),
- OpenTime = timer:now_diff(os:timestamp(), T0) / 1000,
- couch_stats:update_histogram([couchdb, db_open_time], OpenTime),
DbPid = couch_db:get_pid(Db),
case ets:lookup(couch_dbs, DbName) of
[] ->
@@ -480,7 +501,7 @@ handle_call({open_result, T0, DbName, {ok, Db}}, {Opener, _}, Server) ->
[gen_server:reply(Waiter, {ok, Db}) || Waiter <- Waiters],
% Cancel the creation request if it exists.
case ReqType of
- {create, DbName, _Engine, _Options, CrFrom} ->
+ {create, DbName, _Options, CrFrom} ->
gen_server:reply(CrFrom, file_exists);
_ ->
ok
@@ -508,9 +529,9 @@ handle_call({open_result, T0, DbName, {ok, Db}}, {Opener, _}, Server) ->
exit(couch_db:get_pid(Db), kill),
{reply, ok, Server}
end;
-handle_call({open_result, T0, DbName, {error, eexist}}, From, Server) ->
- handle_call({open_result, T0, DbName, file_exists}, From, Server);
-handle_call({open_result, _T0, DbName, Error}, {Opener, _}, Server) ->
+handle_call({open_result, DbName, {error, eexist}}, From, Server) ->
+ handle_call({open_result, DbName, file_exists}, From, Server);
+handle_call({open_result, DbName, Error}, {Opener, _}, Server) ->
case ets:lookup(couch_dbs, DbName) of
[] ->
% db was deleted during async open
@@ -520,8 +541,8 @@ handle_call({open_result, _T0, DbName, Error}, {Opener, _}, Server) ->
true = ets:delete(couch_dbs, DbName),
true = ets:delete(couch_dbs_pid_to_name, Opener),
NewServer = case ReqType of
- {create, DbName, Engine, Options, CrFrom} ->
- open_async(Server, CrFrom, DbName, Engine, Options);
+ {create, DbName, Options, CrFrom} ->
+ open_async(Server, CrFrom, DbName, Options);
_ ->
Server
end,
@@ -534,18 +555,11 @@ handle_call({open_result, _T0, DbName, Error}, {Opener, _}, Server) ->
handle_call({open, DbName, Options}, From, Server) ->
case ets:lookup(couch_dbs, DbName) of
[] ->
- DbNameList = binary_to_list(DbName),
- case check_dbname(Server, DbNameList) of
- ok ->
- case make_room(Server, Options) of
- {ok, Server2} ->
- {ok, Engine} = get_engine(Server2, DbNameList),
- {noreply, open_async(Server2, From, DbName, Engine, Options)};
- {CloseError, Server2} ->
- {reply, CloseError, Server2}
- end;
- Error ->
- {reply, Error, Server}
+ case make_room(Server, Options) of
+ {ok, Server2} ->
+ {noreply, open_async(Server2, From, DbName, Options)};
+ {CloseError, Server2} ->
+ {reply, CloseError, Server2}
end;
[#entry{waiters = Waiters} = Entry] when is_list(Waiters) ->
true = ets:insert(couch_dbs, Entry#entry{waiters = [From | Waiters]}),
@@ -559,36 +573,25 @@ handle_call({open, DbName, Options}, From, Server) ->
{reply, {ok, Db}, Server}
end;
handle_call({create, DbName, Options}, From, Server) ->
- DbNameList = binary_to_list(DbName),
- case get_engine(Server, DbNameList, Options) of
- {ok, Engine} ->
- case check_dbname(Server, DbNameList) of
- ok ->
- case ets:lookup(couch_dbs, DbName) of
- [] ->
- case make_room(Server, Options) of
- {ok, Server2} ->
- {noreply, open_async(Server2, From, DbName, Engine,
- [create | Options])};
- CloseError ->
- {reply, CloseError, Server}
- end;
- [#entry{req_type = open} = Entry] ->
- % We're trying to create a database while someone is in
- % the middle of trying to open it. We allow one creator
- % to wait while we figure out if it'll succeed.
+ case ets:lookup(couch_dbs, DbName) of
+ [] ->
+ case make_room(Server, Options) of
+ {ok, Server2} ->
CrOptions = [create | Options],
- Req = {create, DbName, Engine, CrOptions, From},
- true = ets:insert(couch_dbs, Entry#entry{req_type = Req}),
- {noreply, Server};
- [_AlreadyRunningDb] ->
- {reply, file_exists, Server}
- end;
- Error ->
- {reply, Error, Server}
+ {noreply, open_async(Server2, From, DbName, CrOptions)};
+ {CloseError, Server2} ->
+ {reply, CloseError, Server2}
end;
- Error ->
- {reply, Error, Server}
+ [#entry{req_type = open} = Entry] ->
+ % We're trying to create a database while someone is in
+ % the middle of trying to open it. We allow one creator
+ % to wait while we figure out if it'll succeed.
+ CrOptions = [create | Options],
+ Req = {create, DbName, CrOptions, From},
+ true = ets:insert(couch_dbs, Entry#entry{req_type = Req}),
+ {noreply, Server};
+ [_AlreadyRunningDb] ->
+ {reply, file_exists, Server}
end;
handle_call({delete, DbName, Options}, _From, Server) ->
DbNameList = binary_to_list(DbName),