You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2012/08/14 22:19:00 UTC

git commit: COUCHDB-1444 Broken couch_view_group

Updated Branches:
  refs/heads/1.2.x bb8397707 -> 53490d915


COUCHDB-1444 Broken couch_view_group

It appears that exit signals were propogating between couch_view_updater
processes through couch_os_process and friends. This changes the use of
the 'EXIT' signal to a '$gen_cast' message.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/53490d91
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/53490d91
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/53490d91

Branch: refs/heads/1.2.x
Commit: 53490d915038c04ed47f0c8a00b771583c483b0e
Parents: bb83977
Author: Paul Joseph Davis <da...@apache.org>
Authored: Fri Aug 10 10:45:03 2012 -0500
Committer: Paul Joseph Davis <da...@apache.org>
Committed: Fri Aug 10 11:41:12 2012 -0500

----------------------------------------------------------------------
 src/couchdb/couch_view_compactor.erl |   26 +++++++++---
 src/couchdb/couch_view_group.erl     |   63 ++++++++++++++---------------
 src/couchdb/couch_view_updater.erl   |    8 ++-
 3 files changed, 56 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/53490d91/src/couchdb/couch_view_compactor.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_view_compactor.erl b/src/couchdb/couch_view_compactor.erl
index 58600c8..a7dc68c 100644
--- a/src/couchdb/couch_view_compactor.erl
+++ b/src/couchdb/couch_view_compactor.erl
@@ -117,13 +117,27 @@ maybe_retry_compact(#db{name = DbName} = Db, GroupId, NewGroup) ->
         couch_db:close(Db);
     update ->
         {ok, Db2} = couch_db:reopen(Db),
-        {_, Ref} = erlang:spawn_monitor(fun() ->
-            couch_view_updater:update(nil, NewGroup, Db2)
+        Self = self(),
+        {MPid, MRef} = erlang:spawn_monitor(fun() ->
+            couch_view_updater:update(Self, NewGroup, Db2)
         end),
-        receive
-        {'DOWN', Ref, _, _, {new_group, NewGroup2}} ->
-            maybe_retry_compact(Db2, GroupId, NewGroup2)
-        end
+        NewGroup1 = get_new_group(MPid, MRef),
+        erlang:demonitor(MRef, [flush]),
+        maybe_retry_compact(Db2, GroupId, NewGroup1)
+    end.
+
+get_new_group(Pid, Ref) ->
+    receive
+        {'DOWN', Ref, _, _, {new_group, NewGroup}} ->
+            NewGroup;
+        {'DOWN', Ref, _, _, Reason} ->
+            erlang:error({view_compaction_error, Reason});
+        {'$gen_cast', {Pid, new_group, NewGroup}} ->
+            NewGroup;
+        {'$gen_cast', {partial_update, _, _}} ->
+            get_new_group(Pid, Ref);
+        Else ->
+            erlang:error({view_compaction_error, Else})
     end.
 
 %% @spec compact_view(View, EmptyView, Retry, Acc) -> {CompactView, NewAcc}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/53490d91/src/couchdb/couch_view_group.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_view_group.erl b/src/couchdb/couch_view_group.erl
index fee2547..5f83c05 100644
--- a/src/couchdb/couch_view_group.erl
+++ b/src/couchdb/couch_view_group.erl
@@ -271,6 +271,37 @@ handle_cast({partial_update, Pid, #group{sig=GroupSig}=NewGroup}, #group_state{u
 handle_cast({partial_update, _, _}, State) ->
     %% message from an old (probably pre-compaction) updater; ignore
     {noreply, State};
+handle_cast({FromPid, new_group, #group{sig=GroupSig} = Group},
+        #group_state{db_name=DbName,
+            group=#group{sig=GroupSig},
+            updater_pid=UpPid,
+            ref_counter=RefCounter,
+            waiting_list=WaitList,
+            shutdown=Shutdown,
+            waiting_commit=WaitingCommit}=State) when UpPid == FromPid ->
+    if not WaitingCommit ->
+        erlang:send_after(1000, self(), delayed_commit);
+    true -> ok
+    end,
+    case reply_with_group(Group, WaitList, [], RefCounter) of
+    [] ->
+        case Shutdown of
+        true ->
+            {stop, normal, State};
+        false ->
+            {noreply, State#group_state{waiting_commit=true, waiting_list=[],
+                group=Group, updater_pid=nil}}
+        end;
+    StillWaiting ->
+        % we still have some waiters, reopen the database and reupdate the index
+        Owner = self(),
+        Pid = spawn_link(fun() -> couch_view_updater:update(Owner, Group, DbName) end),
+        {noreply, State#group_state{waiting_commit=true,
+                waiting_list=StillWaiting, updater_pid=Pid}}
+    end;
+handle_cast({_, new_group, _}, State) ->
+    %% message from an old (probably pre-compaction) updater; ignore
+    {noreply, State};
 handle_cast(ddoc_updated, State) ->
     #group_state{
         db_name = DbName,
@@ -317,38 +348,6 @@ handle_info(delayed_commit, #group_state{db_name=DbName,group=Group}=State) ->
         {noreply, State#group_state{waiting_commit=true}}
     end;
 
-handle_info({'EXIT', FromPid, {new_group, #group{sig=GroupSig} = Group}},
-        #group_state{db_name=DbName,
-            group=#group{sig=GroupSig},
-            updater_pid=UpPid,
-            ref_counter=RefCounter,
-            waiting_list=WaitList,
-            shutdown=Shutdown,
-            waiting_commit=WaitingCommit}=State) when UpPid == FromPid ->
-    if not WaitingCommit ->
-        erlang:send_after(1000, self(), delayed_commit);
-    true -> ok
-    end,
-    case reply_with_group(Group, WaitList, [], RefCounter) of
-    [] ->
-        case Shutdown of
-        true ->
-            {stop, normal, State};
-        false ->
-            {noreply, State#group_state{waiting_commit=true, waiting_list=[],
-                group=Group, updater_pid=nil}}
-        end;
-    StillWaiting ->
-        % we still have some waiters, reopen the database and reupdate the index
-        Owner = self(),
-        Pid = spawn_link(fun() -> couch_view_updater:update(Owner, Group, DbName) end),
-        {noreply, State#group_state{waiting_commit=true,
-                waiting_list=StillWaiting, updater_pid=Pid}}
-    end;
-handle_info({'EXIT', _, {new_group, _}}, State) ->
-    %% message from an old (probably pre-compaction) updater; ignore
-    {noreply, State};
-
 handle_info({'EXIT', UpPid, reset},
         #group_state{init_args=InitArgs, updater_pid=UpPid} = State) ->
     case prepare_group(InitArgs, true) of

http://git-wip-us.apache.org/repos/asf/couchdb/blob/53490d91/src/couchdb/couch_view_updater.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_view_updater.erl b/src/couchdb/couch_view_updater.erl
index 4aee586..6a5530e 100644
--- a/src/couchdb/couch_view_updater.erl
+++ b/src/couchdb/couch_view_updater.erl
@@ -92,9 +92,11 @@ update(Owner, Group, #db{name = DbName} = Db) ->
             end,
             ok, []),
     couch_work_queue:close(MapQueue),
-    receive {new_group, NewGroup} ->
-        exit({new_group,
-                NewGroup#group{current_seq=couch_db:get_update_seq(Db)}})
+    receive {new_group, NewGroup0} ->
+        NewGroup = NewGroup0#group{
+            current_seq=couch_db:get_update_seq(Db)
+        },
+        gen_server:cast(Owner, {self(), new_group, NewGroup})
     end.