Fix COUCHDB-1363 - race condition in couch_changes It's necessary to re-open the #db after subscribing to notifications so that updates are not lost. In practice, this is rarely problematic because the next change will cause everything to catch up, but if a quick burst of changes happens while replication is starting the replication can go stale. Detected by intermittent replicator_db js test failures.
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/1bbe6197 Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/1bbe6197 Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/1bbe6197 Branch: refs/heads/1.2.x Commit: 1bbe61973a8d6b3a7c0d8789cdd01bb86499285d Parents: 7f9376c Author: Randall Leeds <[email protected]> Authored: Wed Dec 14 20:12:08 2011 -0800 Committer: Randall Leeds <[email protected]> Committed: Thu Dec 15 16:47:41 2011 -0800 ---------------------------------------------------------------------- src/couchdb/couch_changes.erl | 22 ++++++++++++++-------- 1 files changed, 14 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb/blob/1bbe6197/src/couchdb/couch_changes.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_changes.erl b/src/couchdb/couch_changes.erl index 1de24d4..756a45a 100644 --- a/src/couchdb/couch_changes.erl +++ b/src/couchdb/couch_changes.erl @@ -35,7 +35,7 @@ }). %% @type Req -> #httpd{} | {json_req, JsonObj()} -handle_changes(Args1, Req, Db) -> +handle_changes(Args1, Req, Db0) -> #changes_args{ style = Style, filter = FilterName, @@ -43,13 +43,17 @@ handle_changes(Args1, Req, Db) -> dir = Dir, since = Since } = Args1, - {FilterFun, FilterArgs} = make_filter_fun(FilterName, Style, Req, Db), + {FilterFun, FilterArgs} = make_filter_fun(FilterName, Style, Req, Db0), Args = Args1#changes_args{filter_fun = FilterFun, filter_args = FilterArgs}, - StartSeq = case Dir of - rev -> - couch_db:get_update_seq(Db); - fwd -> - Since + Start = fun() -> + {ok, Db} = couch_db:reopen(Db0), + StartSeq = case Dir of + rev -> + couch_db:get_update_seq(Db); + fwd -> + Since + end, + {Db, StartSeq} end, % begin timer to deal with heartbeat when filter function fails case Args#changes_args.heartbeat of @@ -64,12 +68,13 @@ handle_changes(Args1, Req, Db) -> {Callback, UserAcc} = get_callback_acc(CallbackAcc), Self = self(), {ok, Notify} = couch_db_update_notifier:start_link( - fun({_, DbName}) when DbName == Db#db.name -> + fun({_, DbName}) when Db0#db.name == DbName -> Self ! db_updated; (_) -> ok end ), + {Db, StartSeq} = Start(), UserAcc2 = start_sending_changes(Callback, UserAcc, Feed), {Timeout, TimeoutFun} = get_changes_timeout(Args, Callback), Acc0 = build_acc(Args, Callback, UserAcc2, Db, StartSeq, @@ -89,6 +94,7 @@ handle_changes(Args1, Req, Db) -> {Callback, UserAcc} = get_callback_acc(CallbackAcc), UserAcc2 = start_sending_changes(Callback, UserAcc, Feed), {Timeout, TimeoutFun} = get_changes_timeout(Args, Callback), + {Db, StartSeq} = Start(), Acc0 = build_acc(Args#changes_args{feed="normal"}, Callback, UserAcc2, Db, StartSeq, <<>>, Timeout, TimeoutFun), {ok, #changes_acc{seq = LastSeq, user_acc = UserAcc3}} =
