You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ko...@apache.org on 2017/03/01 16:39:07 UTC
[20/50] couch commit: updated refs/heads/2971-count-distinct to
ee32cd5
Handle open_result message that arrives after the delete
Opening a database is asynchronous, therefore it's possible for the
database to have been deleted before the open is complete. The
open_result code assumes this doesn't happen, so when it does,
couch_server crashes, taking the couch_dbs ETS table with it.
Explicitly handle the case and keep on keeping on.
COUCHDB-3241
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/54890e1b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/54890e1b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/54890e1b
Branch: refs/heads/2971-count-distinct
Commit: 54890e1b8f1d44225ed559ec53f7bf1f4402435b
Parents: ac69856
Author: Robert Newson <rn...@apache.org>
Authored: Wed Nov 23 15:20:11 2016 +0000
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Nov 23 15:20:11 2016 +0000
----------------------------------------------------------------------
src/couch_server.erl | 73 +++++++++++++++++++++++++++--------------------
1 file changed, 42 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/54890e1b/src/couch_server.erl
----------------------------------------------------------------------
diff --git a/src/couch_server.erl b/src/couch_server.erl
index 417c791..b60017a 100644
--- a/src/couch_server.erl
+++ b/src/couch_server.erl
@@ -334,46 +334,57 @@ handle_call({set_max_dbs_open, Max}, _From, Server) ->
handle_call(get_server, _From, Server) ->
{reply, {ok, Server}, Server};
handle_call({open_result, T0, DbName, {ok, Db}}, {FromPid, _Tag}, Server) ->
- link(Db#db.main_pid),
true = ets:delete(couch_dbs_pid_to_name, FromPid),
OpenTime = timer:now_diff(os:timestamp(), T0) / 1000,
couch_stats:update_histogram([couchdb, db_open_time], OpenTime),
% icky hack of field values - compactor_pid used to store clients
% and fd used to possibly store a creation request
- [#db{fd=ReqType, compactor_pid=Froms}] = ets:lookup(couch_dbs, DbName),
- [gen_server:reply(From, {ok, Db}) || From <- Froms],
- % Cancel the creation request if it exists.
- case ReqType of
- {create, DbName, _Filepath, _Options, CrFrom} ->
- gen_server:reply(CrFrom, file_exists);
- _ ->
- ok
- end,
- true = ets:insert(couch_dbs, Db),
- true = ets:insert(couch_dbs_pid_to_name, {Db#db.main_pid, DbName}),
- Lru = case couch_db:is_system_db(Db) of
- false ->
- couch_lru:insert(DbName, Server#server.lru);
- true ->
- Server#server.lru
- end,
- {reply, ok, Server#server{lru = Lru}};
+ case ets:lookup(couch_dbs, DbName) of
+ [] ->
+ % db was deleted during async open
+ exit(Db#db.main_pid, kill),
+ {reply, ok, Server};
+ [#db{fd=ReqType, compactor_pid=Froms}] ->
+ link(Db#db.main_pid),
+ [gen_server:reply(From, {ok, Db}) || From <- Froms],
+ % Cancel the creation request if it exists.
+ case ReqType of
+ {create, DbName, _Filepath, _Options, CrFrom} ->
+ gen_server:reply(CrFrom, file_exists);
+ _ ->
+ ok
+ end,
+ true = ets:insert(couch_dbs, Db),
+ true = ets:insert(couch_dbs_pid_to_name, {Db#db.main_pid, DbName}),
+ Lru = case couch_db:is_system_db(Db) of
+ false ->
+ couch_lru:insert(DbName, Server#server.lru);
+ true ->
+ Server#server.lru
+ end,
+ {reply, ok, Server#server{lru = Lru}}
+ 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}, {FromPid, _Tag}, Server) ->
% icky hack of field values - compactor_pid used to store clients
- [#db{fd=ReqType, compactor_pid=Froms}=Db] = ets:lookup(couch_dbs, DbName),
- [gen_server:reply(From, Error) || From <- Froms],
- couch_log:info("open_result error ~p for ~s", [Error, DbName]),
- true = ets:delete(couch_dbs, DbName),
- true = ets:delete(couch_dbs_pid_to_name, FromPid),
- NewServer = case ReqType of
- {create, DbName, Filepath, Options, CrFrom} ->
- open_async(Server, CrFrom, DbName, Filepath, Options);
- _ ->
- Server
- end,
- {reply, ok, db_closed(NewServer, Db#db.options)};
+ case ets:lookup(couch_dbs, DbName) of
+ [] ->
+ % db was deleted during async open
+ {reply, ok, Server};
+ [#db{fd=ReqType, compactor_pid=Froms}=Db] ->
+ [gen_server:reply(From, Error) || From <- Froms],
+ couch_log:info("open_result error ~p for ~s", [Error, DbName]),
+ true = ets:delete(couch_dbs, DbName),
+ true = ets:delete(couch_dbs_pid_to_name, FromPid),
+ NewServer = case ReqType of
+ {create, DbName, Filepath, Options, CrFrom} ->
+ open_async(Server, CrFrom, DbName, Filepath, Options);
+ _ ->
+ Server
+ end,
+ {reply, ok, db_closed(NewServer, Db#db.options)}
+ end;
handle_call({open, DbName, Options}, From, Server) ->
case ets:lookup(couch_dbs, DbName) of
[] ->