summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoan Touzet <wohali@users.noreply.github.com>2019-01-18 15:16:19 -0500
committerGitHub <noreply@github.com>2019-01-18 15:16:19 -0500
commit6cb050610abde7a822d340b2652cba36b4f2b287 (patch)
treeb54b2694f74ed5d47879687270c40f9714c8597e
parent8d2af71f2896d5f75ceb0f780993493fcecdf49d (diff)
downloadcouchdb-6cb050610abde7a822d340b2652cba36b4f2b287.tar.gz
Add new /{db}/_sync_shards endpoint (admin-only) (#1811)
This server admin-only endpoint forces an n-way sync of all shards across all nodes on which they are hosted. This can be useful for an administrator adding a new node to the cluster, after updating _dbs so that the new node hosts an existing db with content, to force the new node to sync all of that db's shards. Users may want to bump their `[mem3] sync_concurrency` value to a larger figure for the duration of the shards sync. Closes #1807
-rw-r--r--src/chttpd/src/chttpd_auth_request.erl2
-rw-r--r--src/mem3/src/mem3_httpd.erl20
-rw-r--r--src/mem3/src/mem3_httpd_handlers.erl1
3 files changed, 22 insertions, 1 deletions
diff --git a/src/chttpd/src/chttpd_auth_request.erl b/src/chttpd/src/chttpd_auth_request.erl
index 9110ed6bc..f85eb9722 100644
--- a/src/chttpd/src/chttpd_auth_request.erl
+++ b/src/chttpd/src/chttpd_auth_request.erl
@@ -70,6 +70,8 @@ authorize_request_int(#httpd{path_parts=[_DbName, <<"_compact">>|_]}=Req) ->
require_db_admin(Req);
authorize_request_int(#httpd{path_parts=[_DbName, <<"_view_cleanup">>]}=Req) ->
require_db_admin(Req);
+authorize_request_int(#httpd{path_parts=[_DbName, <<"_sync_shards">>]}=Req) ->
+ require_admin(Req);
authorize_request_int(#httpd{path_parts=[_DbName|_]}=Req) ->
db_authorization_check(Req).
diff --git a/src/mem3/src/mem3_httpd.erl b/src/mem3/src/mem3_httpd.erl
index 571f06370..c922141b1 100644
--- a/src/mem3/src/mem3_httpd.erl
+++ b/src/mem3/src/mem3_httpd.erl
@@ -12,7 +12,8 @@
-module(mem3_httpd).
--export([handle_membership_req/1, handle_shards_req/2]).
+-export([handle_membership_req/1, handle_shards_req/2,
+ handle_sync_req/2]).
%% includes
-include_lib("mem3/include/mem3.hrl").
@@ -52,6 +53,16 @@ handle_shards_req(#httpd{path_parts=[_DbName, <<"_shards">>]}=Req, _Db) ->
handle_shards_req(#httpd{path_parts=[_DbName, <<"_shards">>, _DocId]}=Req, _Db) ->
chttpd:send_method_not_allowed(Req, "GET").
+handle_sync_req(#httpd{method='POST',
+ path_parts=[_DbName, <<"_sync_shards">>]} = Req, Db) ->
+ DbName = mem3:dbname(couch_db:name(Db)),
+ ShardList = [S#shard.name || S <- mem3:ushards(DbName)],
+ [ sync_shard(S) || S <- ShardList ],
+ chttpd:send_json(Req, 202, {[{ok, true}]});
+handle_sync_req(Req, _) ->
+ chttpd:send_method_not_allowed(Req, "POST").
+
+
%%
%% internal
%%
@@ -64,3 +75,10 @@ json_shards([#shard{node=Node, range=[B,E]} | Rest], AccIn) ->
HexEnd = couch_util:to_hex(<<E:32/integer>>),
Range = list_to_binary(HexBeg ++ "-" ++ HexEnd),
json_shards(Rest, dict:append(Range, Node, AccIn)).
+
+sync_shard(ShardName) ->
+ Shards = mem3_shards:for_shard_name(ShardName),
+ [rpc:call(S1#shard.node, mem3_sync, push, [S1, S2#shard.node]) ||
+ S1 <- Shards, S2 <- Shards, S1 =/= S2],
+ ok.
+
diff --git a/src/mem3/src/mem3_httpd_handlers.erl b/src/mem3/src/mem3_httpd_handlers.erl
index d8e138c15..7cbd9fe5f 100644
--- a/src/mem3/src/mem3_httpd_handlers.erl
+++ b/src/mem3/src/mem3_httpd_handlers.erl
@@ -18,6 +18,7 @@ url_handler(<<"_membership">>) -> fun mem3_httpd:handle_membership_req/1;
url_handler(_) -> no_match.
db_handler(<<"_shards">>) -> fun mem3_httpd:handle_shards_req/2;
+db_handler(<<"_sync_shards">>) -> fun mem3_httpd:handle_sync_req/2;
db_handler(_) -> no_match.
design_handler(_) -> no_match.