You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2019/02/04 19:33:27 UTC

[couchdb] branch shard-split updated: Add a consistent reason to state API queries.

This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch shard-split
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/shard-split by this push:
     new 9ee3d08  Add a consistent reason to state API queries.
9ee3d08 is described below

commit 9ee3d08a02662c083f8e67aab56cde2d52db117b
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Mon Feb 4 14:27:05 2019 -0500

    Add a consistent reason to state API queries.
    
    This is both for _reshard/state and _reshard/ GET queries.
    
    ```
    http $DB1/_reshard/state
    
    {
        "reason": null,
        "state": "running"
    }
    ```
    
    ```
    http $DB1/_reshard/
    
    {
        "completed": 1,
        "failed": 0,
        "running": 0,
        "state": "running",
        "state_reason": null,
        "stopped": 0,
        "total": 1
    }
    ```
    
    Then when stopped:
    
    ```
    http put $DB1/_reshard/state state=stopped reason="Rebalancing in progress"
    ```
    
    ```
    http $DB1/_reshard/
    
    {
        "completed": 1,
        "failed": 0,
        "running": 0,
        "state": "stopped",
        "state_reason": "Rebalancing in progress",
        "stopped": 0,
        "total": 1
    }
    ```
    
    ```
    http $DB1/_reshard/state
    
    {
        "reason": "Rebalancing in progress",
        "state": "stopped"
    }
    ```
---
 src/mem3/src/mem3_reshard.erl            |  2 +-
 src/mem3/src/mem3_reshard_httpd.erl      |  7 ++--
 src/mem3/src/mem3_reshard_httpd_util.erl | 62 +++++++++++++++++++++-----------
 3 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/src/mem3/src/mem3_reshard.erl b/src/mem3/src/mem3_reshard.erl
index 52c6f95..c9cd29b 100644
--- a/src/mem3/src/mem3_reshard.erl
+++ b/src/mem3/src/mem3_reshard.erl
@@ -187,7 +187,7 @@ handle_call(start, _From, #state{state = stopped} = State) ->
     State1 = State#state{
         state = running,
         time_updated = now_sec(),
-        state_info = info_update(reason, <<"Restarted">>, State#state.state_info)
+        state_info = info_delete(reason, State#state.state_info)
     },
     ok = mem3_reshard_store:store_state(State1),
     State2 = reload_jobs(State1),
diff --git a/src/mem3/src/mem3_reshard_httpd.erl b/src/mem3/src/mem3_reshard_httpd.erl
index efa3a5c..8ed4755 100644
--- a/src/mem3/src/mem3_reshard_httpd.erl
+++ b/src/mem3/src/mem3_reshard_httpd.erl
@@ -45,8 +45,8 @@ handle_reshard_req(#httpd{path_parts=[_]} = Req) ->
 %
 handle_reshard_req(#httpd{method='GET',
         path_parts=[_, ?STATE]} = Req) ->
-    State = mem3_reshard_httpd_util:get_shard_splitting_state(),
-    send_json(Req, {[{state, State}]});
+    {State, Reason} = mem3_reshard_httpd_util:get_shard_splitting_state(),
+    send_json(Req, {[{state, State}, {reason, Reason}]});
 
 % PUT /_reshard/state
 %
@@ -130,6 +130,9 @@ handle_reshard_req(#httpd{method = 'POST',
 handle_reshard_req(#httpd{path_parts=[_, ?JOBS]} = Req) ->
     send_method_not_allowed(Req, "GET,HEAD,POST");
 
+handle_reshard_req(#httpd{path_parts=[_, _]} = Req) ->
+    throw(not_found);
+
 
 % GET /_reshard/jobs/$jobid
 %
diff --git a/src/mem3/src/mem3_reshard_httpd_util.erl b/src/mem3/src/mem3_reshard_httpd_util.erl
index 4718bd5..8c99b19 100644
--- a/src/mem3/src/mem3_reshard_httpd_util.erl
+++ b/src/mem3/src/mem3_reshard_httpd_util.erl
@@ -205,33 +205,55 @@ get_summary() ->
     {Replies, _Bad} = rpc:multicall(Nodes, mem3_reshard, get_state, []),
     Stats0 = #{running => 0, total => 0, completed => 0, failed => 0,
         stopped => 0},
-    {Stats, States} = lists:foldl(fun({Res}, {Stats, States}) ->
-       Stats1 = maps:map(fun(Stat, OldVal) ->
+    StatsF = lists:foldl(fun({Res}, Stats) ->
+       maps:map(fun(Stat, OldVal) ->
            OldVal + couch_util:get_value(Stat, Res, 0)
-       end, Stats),
-       NewStates = [couch_util:get_value(state, Res) | States],
-       {Stats1, NewStates}
-    end, {Stats0, []}, Replies),
-    State = case lists:member(<<"running">>, States) of
-        true -> running;
-        false -> stopped
-    end,
-    {[{state, State}] ++ lists:sort(maps:to_list(Stats))}.
+       end, Stats)
+    end, Stats0, Replies),
+    {State, Reason} = state_and_reason(Replies),
+    {[{state, State}, {state_reason, Reason}] ++ lists:sort(maps:to_list(StatsF))}.
 
 
 get_shard_splitting_state() ->
     Nodes = mem3_util:live_nodes(),
     {Replies, _Bad} = rpc:multicall(Nodes, mem3_reshard, get_state, []),
-    Running = lists:foldl(fun({Res}, R) ->
-       case couch_util:get_value(state, Res) of
-           <<"running">> -> R + 1;
-           _ -> R
+    state_and_reason(Replies).
+
+
+state_and_reason(StateReplies) ->
+    AccF = lists:foldl(fun({ResProps}, Acc) ->
+       Reason = get_reason(ResProps),
+       case couch_util:get_value(state, ResProps) of
+           <<"running">> -> orddict:append(running, Reason, Acc);
+           <<"stopped">> -> orddict:append(stopped, Reason, Acc);
+           undefined -> Acc
        end
-    end, 0, Replies),
-    % If at least one node is "running", then overall state is "running"
-    case Running > 0 of
-        true -> running;
-        false -> stopped
+    end, orddict:from_list([{running, []}, {stopped, []}]), StateReplies),
+    Running = orddict:fetch(running, AccF),
+    case length(Running) > 0 of
+        true ->
+            Reason = pick_reason(Running),
+            {running, Reason};
+        false ->
+            Reason = pick_reason(orddict:fetch(stopped, AccF)),
+            {stopped, Reason}
+    end.
+
+
+pick_reason(Reasons) ->
+    Reasons1 = lists:usort(Reasons),
+    Reasons2 = [R || R <- Reasons1, R =/= undefined],
+    case Reasons2 of
+        [] -> null;
+        [R1 | _] -> R1
+    end.
+
+
+get_reason(StateProps) when is_list(StateProps) ->
+    case couch_util:get_value(state_info, StateProps) of
+        [] -> undefined;
+        undefined -> undefined;
+        {SInfoProps} -> couch_util:get_value(reason, SInfoProps)
     end.