Verify that DB is in couch_dbs before updating This patch fixes a bug where there could be a db_updated message in the couch_server message queue, but the updater process could be dead and removed from the couch_dbs ets table. While this patch doesn't change the possibility of that state, it makes the couch_server db_updated function clause to verify that 1) the DB is in the couch_dbs ets table and 2) that the instance_start_time of the updated DB matches the instance_start_time of the couch_dbs entry. If the DB isn't in the couch_dbs ets table it means that it was removed from the LRU. If the two instance_start_times don't match, it means that the old couch_dbs entry was expired from the LRU and re-inserted before the monitor exit message was processed.
BugzID: 21179 Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/41b61b9a Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/41b61b9a Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/41b61b9a Branch: refs/heads/windsor-merge-209 Commit: 41b61b9a2f07e62dc20a84be85f328dd225f89c9 Parents: 9f16b07 Author: Benjamin Bastian <[email protected]> Authored: Mon Jul 22 15:41:54 2013 -0700 Committer: Robert Newson <[email protected]> Committed: Tue Aug 5 17:35:48 2014 +0100 ---------------------------------------------------------------------- src/couch_server.erl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/41b61b9a/src/couch_server.erl ---------------------------------------------------------------------- diff --git a/src/couch_server.erl b/src/couch_server.erl index e741720..fd4691c 100644 --- a/src/couch_server.erl +++ b/src/couch_server.erl @@ -483,13 +483,22 @@ handle_call({delete, DbName, Options}, _From, Server) -> Error -> {reply, Error, Server} end; -handle_call({db_updated, #db{name = DbName} = Db}, _From, Server) -> - true = ets:insert(couch_dbs, Db), - Lru = case couch_db:is_system_db(Db) of - false -> couch_lru:update(DbName, Server#server.lru); - true -> Server#server.lru +handle_call({db_updated, #db{}=Db}, _From, Server0) -> + #db{name = DbName, instance_start_time = StartTime} = Db, + Server = try ets:lookup_element(couch_dbs, DbName, #db.instance_start_time) of + StartTime -> + true = ets:insert(couch_dbs, Db), + Lru = case couch_db:is_system_db(Db) of + false -> couch_lru:update(DbName, Server0#server.lru); + true -> Server0#server.lru + end, + Server0#server{lru = Lru}; + _ -> + Server0 + catch _:_ -> + Server0 end, - {reply, ok, Server#server{lru = Lru}}. + {reply, ok, Server}. handle_cast({update_lru, DbName}, #server{lru = Lru, update_lru_on_read=true} = Server) -> {noreply, Server#server{lru = couch_lru:update(DbName, Lru)}};
