You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2016/10/07 22:39:30 UTC
kudu git commit: [tools] Implement a manual leader_step_down for a
tablet
Repository: kudu
Updated Branches:
refs/heads/master fc5e6a3e7 -> 833abea78
[tools] Implement a manual leader_step_down for a tablet
This change introduces a leader_step_down functionality
under 'kudu tablet'. This tool may be handy to recover from
situations when a single tablet server is overloaded and we want
to kick off a new election to balance the load across the clusters.
Although it is not guaranteed that a different replica will be elected
as the leader, this is an optimistic effort to elect a new tablet
server as the leader for the given tablet in the cluster.
Test: Ran 8000 iterations of leader_step_down test on dist_test.
Also snuck in a small change to display host:port details with
'kudu table list <master_addresses> --list_tablets' command.
Change-Id: Ia046a28a2008f4f5d1e955f57752a32a1ddc5ab8
Reviewed-on: http://gerrit.cloudera.org:8080/4533
Tested-by: Kudu Jenkins
Reviewed-by: Alexey Serbin <as...@cloudera.com>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/833abea7
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/833abea7
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/833abea7
Branch: refs/heads/master
Commit: 833abea787d3ac4bde3e5292c82b3408aad9ba92
Parents: fc5e6a3
Author: Dinesh Bhat <di...@cloudera.com>
Authored: Thu Sep 22 09:56:34 2016 -0700
Committer: Alexey Serbin <as...@cloudera.com>
Committed: Fri Oct 7 22:11:16 2016 +0000
----------------------------------------------------------------------
src/kudu/tools/kudu-admin-test.cc | 91 +++++++++++++++++++++++
src/kudu/tools/kudu-tool-test.cc | 3 +-
src/kudu/tools/tool_action_cluster.cc | 8 +-
src/kudu/tools/tool_action_common.cc | 6 ++
src/kudu/tools/tool_action_common.h | 6 ++
src/kudu/tools/tool_action_local_replica.cc | 32 ++++----
src/kudu/tools/tool_action_remote_replica.cc | 10 +--
src/kudu/tools/tool_action_table.cc | 15 ++--
src/kudu/tools/tool_action_tablet.cc | 81 ++++++++++++++------
src/kudu/tools/tool_action_test.cc | 4 +-
10 files changed, 190 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/kudu-admin-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-admin-test.cc b/src/kudu/tools/kudu-admin-test.cc
index b5aac2c..b5c5f83 100644
--- a/src/kudu/tools/kudu-admin-test.cc
+++ b/src/kudu/tools/kudu-admin-test.cc
@@ -37,6 +37,7 @@ using client::KuduClientBuilder;
using client::KuduSchema;
using client::KuduTableCreator;
using client::sp::shared_ptr;
+using consensus::ConsensusStatePB;
using itest::TabletServerMap;
using itest::TServerDetails;
using std::string;
@@ -153,6 +154,96 @@ TEST_F(AdminCliTest, TestChangeConfig) {
MonoDelta::FromSeconds(10)));
}
+Status GetTermFromConsensus(const vector<TServerDetails*>& tservers,
+ const string& tablet_id,
+ int64 *current_term) {
+ ConsensusStatePB cstate;
+ for (auto& ts : tservers) {
+ RETURN_NOT_OK(
+ itest::GetConsensusState(ts, tablet_id,
+ consensus::CONSENSUS_CONFIG_COMMITTED,
+ MonoDelta::FromSeconds(10), &cstate));
+ if (cstate.has_leader_uuid() && cstate.has_current_term()) {
+ *current_term = cstate.current_term();
+ return Status::OK();
+ }
+ }
+ return Status::NotFound(Substitute(
+ "No leader replica found for tablet $0", tablet_id));
+}
+
+TEST_F(AdminCliTest, TestLeaderStepDown) {
+ FLAGS_num_tablet_servers = 3;
+ FLAGS_num_replicas = 3;
+ BuildAndStart({}, {});
+
+ vector<TServerDetails*> tservers;
+ AppendValuesFromMap(tablet_servers_, &tservers);
+ ASSERT_EQ(FLAGS_num_tablet_servers, tservers.size());
+ for (auto& ts : tservers) {
+ ASSERT_OK(itest::WaitUntilTabletRunning(ts,
+ tablet_id_,
+ MonoDelta::FromSeconds(10)));
+ }
+
+ int64 current_term;
+ ASSERT_OK(GetTermFromConsensus(tservers, tablet_id_,
+ ¤t_term));
+
+ // The leader for the given tablet may change anytime, resulting in
+ // the command returning an error code. Hence checking for term advancement
+ // only if the leader_step_down succeeds. It is also unsafe to check
+ // the term advancement without honoring status of the command since
+ // there may not have been another election in the meanwhile.
+ string stderr;
+ Status s = Subprocess::Call({GetKuduCtlAbsolutePath(),
+ "tablet", "leader_step_down",
+ cluster_->master()->bound_rpc_addr().ToString(),
+ tablet_id_}, nullptr, &stderr);
+ bool not_currently_leader = stderr.find(
+ Status::IllegalState("").CodeAsString()) != string::npos;
+ ASSERT_TRUE(s.ok() || not_currently_leader);
+ if (s.ok()) {
+ int64 new_term;
+ AssertEventually([&]() {
+ ASSERT_OK(GetTermFromConsensus(tservers, tablet_id_,
+ &new_term));
+ ASSERT_GT(new_term, current_term);
+ });
+ }
+}
+
+TEST_F(AdminCliTest, TestLeaderStepDownWhenNotPresent) {
+ FLAGS_num_tablet_servers = 3;
+ FLAGS_num_replicas = 3;
+ BuildAndStart(
+ { "--enable_leader_failure_detection=false" },
+ { "--catalog_manager_wait_for_new_tablets_to_elect_leader=false" });
+ vector<TServerDetails*> tservers;
+ AppendValuesFromMap(tablet_servers_, &tservers);
+ ASSERT_EQ(FLAGS_num_tablet_servers, tservers.size());
+ for (auto& ts : tservers) {
+ ASSERT_OK(itest::WaitUntilTabletRunning(ts,
+ tablet_id_,
+ MonoDelta::FromSeconds(10)));
+ }
+
+ int64 current_term;
+ ASSERT_TRUE(GetTermFromConsensus(tservers, tablet_id_,
+ ¤t_term).IsNotFound());
+ string stdout;
+ ASSERT_OK(Subprocess::Call({
+ GetKuduCtlAbsolutePath(),
+ "tablet",
+ "leader_step_down",
+ cluster_->master()->bound_rpc_addr().ToString(),
+ tablet_id_
+ }, &stdout));
+ ASSERT_STR_CONTAINS(stdout,
+ Substitute("No leader replica found for tablet $0",
+ tablet_id_));
+}
+
TEST_F(AdminCliTest, TestDeleteTable) {
FLAGS_num_tablet_servers = 1;
FLAGS_num_replicas = 1;
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/kudu-tool-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
index 34e0a59..94c5160 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -282,7 +282,8 @@ TEST_F(ToolTest, TestModeHelp) {
}
{
const vector<string> kTabletModeRegexes = {
- "change_config.*Change.*Raft configuration"
+ "change_config.*Change.*Raft configuration",
+ "leader_step_down.*Force the tablet's leader replica to step down"
};
NO_FATALS(RunTestHelp("tablet", kTabletModeRegexes));
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_cluster.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_cluster.cc b/src/kudu/tools/tool_action_cluster.cc
index 513d75b..e5351f2 100644
--- a/src/kudu/tools/tool_action_cluster.cc
+++ b/src/kudu/tools/tool_action_cluster.cc
@@ -28,6 +28,7 @@
#include "kudu/gutil/strings/split.h"
#include "kudu/tools/ksck.h"
#include "kudu/tools/ksck_remote.h"
+#include "kudu/tools/tool_action_common.h"
#include "kudu/util/status.h"
#define PUSH_PREPEND_NOT_OK(s, statuses, msg) do { \
@@ -62,8 +63,6 @@ using std::vector;
namespace {
-const char* const kMasterAddressesArg = "master_addresses";
-
Status RunKsck(const RunnerContext& context) {
const string& master_addresses_str = FindOrDie(context.required_args,
kMasterAddressesArg);
@@ -130,10 +129,7 @@ unique_ptr<Mode> BuildClusterMode() {
ActionBuilder("ksck", &RunKsck)
.Description(desc)
.ExtraDescription(extra_desc)
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addressess where each address is "
- "of form 'hostname:port'" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
.AddOptionalParameter("checksum_scan")
.AddOptionalParameter("checksum_scan_concurrency")
.AddOptionalParameter("checksum_snapshot")
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_common.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_common.cc b/src/kudu/tools/tool_action_common.cc
index 867cc2a..bd0db19 100644
--- a/src/kudu/tools/tool_action_common.cc
+++ b/src/kudu/tools/tool_action_common.cc
@@ -97,6 +97,12 @@ using tserver::TabletServerAdminServiceProxy;
using tserver::TabletServerServiceProxy;
using tserver::WriteRequestPB;
+const char* const kMasterAddressesArg = "master_addresses";
+const char* const kMasterAddressesArgDesc = "Comma-separated list of Kudu "
+ "Master addresses where each address is of form 'hostname:port'";
+const char* const kTabletIdArg = "tablet_id";
+const char* const kTabletIdArgDesc = "Tablet Identifier";
+
namespace {
enum PrintEntryType {
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_common.h
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_common.h b/src/kudu/tools/tool_action_common.h
index d51f656..27284f1 100644
--- a/src/kudu/tools/tool_action_common.h
+++ b/src/kudu/tools/tool_action_common.h
@@ -35,6 +35,12 @@ class ServerStatusPB;
namespace tools {
+// Constants for parameters and descriptions.
+extern const char* const kMasterAddressesArg;
+extern const char* const kMasterAddressesArgDesc;
+extern const char* const kTabletIdArg;
+extern const char* const kTabletIdArgDesc;
+
// Utility methods used by multiple actions across different modes.
// Builds a proxy to a Kudu server running at 'address', returning it in
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_local_replica.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_local_replica.cc b/src/kudu/tools/tool_action_local_replica.cc
index b0455a7..461235e 100644
--- a/src/kudu/tools/tool_action_local_replica.cc
+++ b/src/kudu/tools/tool_action_local_replica.cc
@@ -116,8 +116,8 @@ using tserver::WriteRequestPB;
namespace {
-static const char* const kSeparatorLine =
- "----------------------------------------------------------------------\n";
+const char* const kSeparatorLine =
+ "----------------------------------------------------------------------\n";
string Indent(int indent) {
return string(indent, ' ');
@@ -172,7 +172,7 @@ Status ParsePeerString(const string& peer_str,
Status PrintReplicaUuids(const RunnerContext& context) {
unique_ptr<FsManager> fs_manager;
RETURN_NOT_OK(FsInit(&fs_manager));
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
// Load the cmeta file and print all peer uuids.
unique_ptr<ConsensusMetadata> cmeta;
@@ -186,7 +186,7 @@ Status PrintReplicaUuids(const RunnerContext& context) {
Status RewriteRaftConfig(const RunnerContext& context) {
// Parse tablet ID argument.
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
if (tablet_id != master::SysCatalogTable::kSysCatalogTabletId) {
LOG(WARNING) << "Master will not notice rewritten Raft config of regular "
<< "tablets. A regular Raft config change must occur.";
@@ -238,7 +238,7 @@ Status RewriteRaftConfig(const RunnerContext& context) {
Status CopyFromRemote(const RunnerContext& context) {
// Parse the tablet ID and source arguments.
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
const string& rpc_address = FindOrDie(context.required_args, "source");
HostPort hp;
@@ -259,7 +259,7 @@ Status CopyFromRemote(const RunnerContext& context) {
Status DumpWals(const RunnerContext& context) {
unique_ptr<FsManager> fs_manager;
RETURN_NOT_OK(FsInit(&fs_manager));
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
shared_ptr<LogReader> reader;
RETURN_NOT_OK(LogReader::Open(fs_manager.get(),
@@ -309,7 +309,7 @@ Status ListBlocksInRowSet(const Schema& schema,
Status DumpBlockIdsForLocalReplica(const RunnerContext& context) {
unique_ptr<FsManager> fs_manager;
RETURN_NOT_OK(FsInit(&fs_manager));
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
scoped_refptr<TabletMetadata> meta;
RETURN_NOT_OK(TabletMetadata::Load(fs_manager.get(), tablet_id, &meta));
@@ -567,7 +567,7 @@ Status DumpRowSetInternal(FsManager* fs_manager,
Status DumpRowSet(const RunnerContext& context) {
unique_ptr<FsManager> fs_manager;
RETURN_NOT_OK(FsInit(&fs_manager));
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
scoped_refptr<TabletMetadata> meta;
RETURN_NOT_OK(TabletMetadata::Load(fs_manager.get(), tablet_id, &meta));
@@ -607,7 +607,7 @@ Status DumpRowSet(const RunnerContext& context) {
Status DumpMeta(const RunnerContext& context) {
unique_ptr<FsManager> fs_manager;
RETURN_NOT_OK(FsInit(&fs_manager));
- const string& tablet_id = FindOrDie(context.required_args, "tablet_id");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
RETURN_NOT_OK(DumpTabletMeta(fs_manager.get(), tablet_id, 0));
return Status::OK();
}
@@ -616,7 +616,7 @@ unique_ptr<Mode> BuildDumpMode() {
unique_ptr<Action> dump_block_ids =
ActionBuilder("block_ids", &DumpBlockIdsForLocalReplica)
.Description("Dump the IDs of all blocks belonging to a local replica")
- .AddRequiredParameter({ "tablet_id", "tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.Build();
@@ -624,7 +624,7 @@ unique_ptr<Mode> BuildDumpMode() {
unique_ptr<Action> dump_meta =
ActionBuilder("meta", &DumpMeta)
.Description("Dump the metadata of a local replica")
- .AddRequiredParameter({ "tablet_id", "tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.Build();
@@ -632,7 +632,7 @@ unique_ptr<Mode> BuildDumpMode() {
unique_ptr<Action> dump_rowset =
ActionBuilder("rowset", &DumpRowSet)
.Description("Dump the rowset contents of a local replica")
- .AddRequiredParameter({ "tablet_id", "tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddOptionalParameter("dump_data")
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
@@ -645,7 +645,7 @@ unique_ptr<Mode> BuildDumpMode() {
ActionBuilder("wals", &DumpWals)
.Description("Dump all WAL (write-ahead log) segments of "
"a local replica")
- .AddRequiredParameter({ "tablet_id", "Tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.AddOptionalParameter("print_entries")
@@ -669,7 +669,7 @@ unique_ptr<Mode> BuildLocalReplicaMode() {
ActionBuilder("print_replica_uuids", &PrintReplicaUuids)
.Description("Print all replica UUIDs found in a "
"tablet's Raft configuration")
- .AddRequiredParameter({ "tablet_id", "Tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.Build();
@@ -677,7 +677,7 @@ unique_ptr<Mode> BuildLocalReplicaMode() {
unique_ptr<Action> rewrite_raft_config =
ActionBuilder("rewrite_raft_config", &RewriteRaftConfig)
.Description("Rewrite a replica's Raft configuration")
- .AddRequiredParameter({ "tablet_id", "Tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredVariadicParameter({
"peers", "List of peers where each peer is of "
"form 'uuid:hostname:port'" })
@@ -696,7 +696,7 @@ unique_ptr<Mode> BuildLocalReplicaMode() {
unique_ptr<Action> copy_from_remote =
ActionBuilder("copy_from_remote", &CopyFromRemote)
.Description("Copy a replica from a remote server")
- .AddRequiredParameter({ "tablet_id", "Tablet identifier" })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredParameter({ "source", "Source RPC address of "
"form hostname:port" })
.AddOptionalParameter("fs_wal_dir")
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_remote_replica.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_remote_replica.cc b/src/kudu/tools/tool_action_remote_replica.cc
index e305d4c..0e117a9 100644
--- a/src/kudu/tools/tool_action_remote_replica.cc
+++ b/src/kudu/tools/tool_action_remote_replica.cc
@@ -136,8 +136,6 @@ class ReplicaDumper {
namespace {
const char* const kReasonArg = "reason";
-const char* const kTabletArg = "tablet_id";
-const char* const kTabletDesc = "Tablet identifier";
const char* const kTServerAddressArg = "tserver_address";
const char* const kTServerAddressDesc = "Address of a Kudu Tablet Server of "
"form 'hostname:port'. Port may be omitted if the Tablet Server is bound "
@@ -189,7 +187,7 @@ Status CheckReplicas(const RunnerContext& context) {
Status DeleteReplica(const RunnerContext& context) {
const string& address = FindOrDie(context.required_args, kTServerAddressArg);
- const string& tablet_id = FindOrDie(context.required_args, kTabletArg);
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
const string& reason = FindOrDie(context.required_args, kReasonArg);
ServerStatusPB status;
@@ -220,7 +218,7 @@ Status DeleteReplica(const RunnerContext& context) {
Status DumpReplica(const RunnerContext& context) {
const string& address = FindOrDie(context.required_args, kTServerAddressArg);
- const string& tablet_id = FindOrDie(context.required_args, kTabletArg);
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
unique_ptr<TabletServerServiceProxy> proxy;
RETURN_NOT_OK(BuildProxy(address, tserver::TabletServer::kDefaultPort,
@@ -295,7 +293,7 @@ unique_ptr<Mode> BuildRemoteReplicaMode() {
ActionBuilder("delete", &DeleteReplica)
.Description("Delete a replica from a Kudu Tablet Server")
.AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
- .AddRequiredParameter({ kTabletArg, kTabletDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredParameter({ kReasonArg, "Reason for deleting the replica" })
.Build();
@@ -303,7 +301,7 @@ unique_ptr<Mode> BuildRemoteReplicaMode() {
ActionBuilder("dump", &DumpReplica)
.Description("Dump the data of a replica on a Kudu Tablet Server")
.AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
- .AddRequiredParameter({ kTabletArg, kTabletDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.Build();
unique_ptr<Action> list =
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_table.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_table.cc b/src/kudu/tools/tool_action_table.cc
index c50e3bd..5296886 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -28,6 +28,7 @@
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/split.h"
+#include "kudu/tools/tool_action_common.h"
#include "kudu/util/status.h"
DEFINE_bool(list_tablets, false,
@@ -49,7 +50,6 @@ using std::vector;
namespace {
-const char* const kMasterAddressesArg = "master_addresses";
const char* const kTableNameArg = "table_name";
Status DeleteTable(const RunnerContext& context) {
@@ -93,7 +93,8 @@ Status ListTables(const RunnerContext& context) {
cout << "T " << token->tablet().id() << "\t";
for (const auto* replica : token->tablet().replicas()) {
cout << "P" << (replica->is_leader() ? "(L) " : " ")
- << replica->ts().uuid() << " ";
+ << replica->ts().uuid() << "(" << replica->ts().hostname()
+ << ":" << replica->ts().port() << ")" << " ";
}
cout << endl;
}
@@ -108,20 +109,14 @@ unique_ptr<Mode> BuildTableMode() {
unique_ptr<Action> delete_table =
ActionBuilder("delete", &DeleteTable)
.Description("Delete a table")
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addresses where each address is "
- "of form 'hostname:port'" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
.AddRequiredParameter({ kTableNameArg, "Name of the table to delete" })
.Build();
unique_ptr<Action> list_tables =
ActionBuilder("list", &ListTables)
.Description("List all tables")
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addresses where each address is "
- "of form 'hostname:port'" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
.AddOptionalParameter("list_tablets")
.Build();
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_tablet.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_tablet.cc b/src/kudu/tools/tool_action_tablet.cc
index 0e57d08..0ebc710 100644
--- a/src/kudu/tools/tool_action_tablet.cc
+++ b/src/kudu/tools/tool_action_tablet.cc
@@ -18,6 +18,7 @@
#include "kudu/tools/tool_action.h"
#include <algorithm>
+#include <iostream>
#include <memory>
#include <string>
#include <vector>
@@ -31,6 +32,7 @@
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/rpc/rpc_controller.h"
+#include "kudu/server/server_base.pb.h"
#include "kudu/tools/tool_action_common.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/status.h"
@@ -47,6 +49,8 @@ using consensus::ChangeConfigType;
using consensus::ConsensusServiceProxy;
using consensus::RaftPeerPB;
using rpc::RpcController;
+using std::cout;
+using std::endl;
using std::string;
using std::unique_ptr;
using std::vector;
@@ -54,10 +58,8 @@ using strings::Substitute;
namespace {
-const char* const kMasterAddressesArg = "master_addresses";
const char* const kReplicaTypeArg = "replica_type";
const char* const kReplicaUuidArg = "replica_uuid";
-const char* const kTabletIdArg = "tablet_id";
Status GetRpcAddressForTS(const client::sp::shared_ptr<KuduClient>& client,
const string& uuid,
@@ -94,6 +96,7 @@ Status GetTabletLeader(const client::sp::shared_ptr<KuduClient>& client,
return Status::OK();
}
}
+
return Status::NotFound(Substitute(
"No leader replica found for tablet $0", tablet_id));
}
@@ -134,13 +137,6 @@ Status ChangeConfig(const RunnerContext& context, ChangeConfigType cc_type) {
string leader_uuid;
HostPort leader_hp;
RETURN_NOT_OK(GetTabletLeader(client, tablet_id, &leader_uuid, &leader_hp));
- vector<Sockaddr> leader_addrs;
- RETURN_NOT_OK(leader_hp.ResolveAddresses(&leader_addrs));
- if (leader_addrs.empty()) {
- return Status::NotFound(
- "Unable to resolve IP address for tablet leader host",
- leader_hp.ToString());
- }
unique_ptr<ConsensusServiceProxy> proxy;
RETURN_NOT_OK(BuildProxy(leader_hp.host(), leader_hp.port(), &proxy));
@@ -172,17 +168,52 @@ Status RemoveReplica(const RunnerContext& context) {
return ChangeConfig(context, consensus::REMOVE_SERVER);
}
+Status LeaderStepDown(const RunnerContext& context) {
+ const string& master_addresses_str = FindOrDie(context.required_args,
+ kMasterAddressesArg);
+ vector<string> master_addresses = strings::Split(master_addresses_str, ",");
+ const string& tablet_id = FindOrDie(context.required_args, kTabletIdArg);
+
+ client::sp::shared_ptr<KuduClient> client;
+ RETURN_NOT_OK(KuduClientBuilder()
+ .master_server_addrs(master_addresses)
+ .Build(&client));
+
+ // If leader is not present, command can gracefully return.
+ string leader_uuid;
+ HostPort leader_hp;
+ Status s = GetTabletLeader(client, tablet_id, &leader_uuid, &leader_hp);
+ if (s.IsNotFound()) {
+ cout << s.ToString() << endl;
+ return Status::OK();
+ }
+ RETURN_NOT_OK(s);
+
+ unique_ptr<ConsensusServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(leader_hp.host(), leader_hp.port(), &proxy));
+
+ consensus::LeaderStepDownRequestPB req;
+ consensus::LeaderStepDownResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(client->default_admin_operation_timeout());
+ req.set_dest_uuid(leader_uuid);
+ req.set_tablet_id(tablet_id);
+
+ RETURN_NOT_OK(proxy->LeaderStepDown(req, &resp, &rpc));
+ if (resp.has_error()) {
+ return StatusFromPB(resp.error().status());
+ }
+ return Status::OK();
+}
+
} // anonymous namespace
unique_ptr<Mode> BuildTabletMode() {
unique_ptr<Action> add_replica =
ActionBuilder("add_replica", &AddReplica)
.Description("Add a new replica to a tablet's Raft configuration")
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addresses where each address is "
- "of form 'hostname:port'" })
- .AddRequiredParameter({ kTabletIdArg, "Tablet Identifier" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredParameter({ kReplicaUuidArg, "New replica's UUID" })
.AddRequiredParameter(
{ kReplicaTypeArg, "New replica's type. Must be VOTER or NON-VOTER."
@@ -193,11 +224,8 @@ unique_ptr<Mode> BuildTabletMode() {
ActionBuilder("change_replica_type", &ChangeReplicaType)
.Description(
"Change the type of an existing replica in a tablet's Raft configuration")
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addresses where each address is "
- "of 'form hostname:port'" })
- .AddRequiredParameter({ kTabletIdArg, "Tablet Identifier" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredParameter({ kReplicaUuidArg, "Existing replica's UUID" })
.AddRequiredParameter(
{ kReplicaTypeArg, "Existing replica's new type. Must be VOTER or NON-VOTER."
@@ -207,14 +235,18 @@ unique_ptr<Mode> BuildTabletMode() {
unique_ptr<Action> remove_replica =
ActionBuilder("remove_replica", &RemoveReplica)
.Description("Remove an existing replica from a tablet's Raft configuration")
- .AddRequiredParameter({
- kMasterAddressesArg,
- "Comma-separated list of Kudu Master addresses where each address is "
- "of form 'hostname:port'" })
- .AddRequiredParameter({ kTabletIdArg, "Tablet Identifier" })
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
.AddRequiredParameter({ kReplicaUuidArg, "Existing replica's UUID" })
.Build();
+ unique_ptr<Action> leader_step_down =
+ ActionBuilder("leader_step_down", &LeaderStepDown)
+ .Description("Force the tablet's leader replica to step down")
+ .AddRequiredParameter({ kMasterAddressesArg, kMasterAddressesArgDesc })
+ .AddRequiredParameter({ kTabletIdArg, kTabletIdArgDesc })
+ .Build();
+
unique_ptr<Mode> change_config =
ModeBuilder("change_config")
.Description("Change a tablet's Raft configuration")
@@ -226,6 +258,7 @@ unique_ptr<Mode> BuildTabletMode() {
return ModeBuilder("tablet")
.Description("Operate on remote Kudu tablets")
.AddMode(std::move(change_config))
+ .AddAction(std::move(leader_step_down))
.Build();
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/833abea7/src/kudu/tools/tool_action_test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_test.cc b/src/kudu/tools/tool_action_test.cc
index 29b8950..5166025 100644
--- a/src/kudu/tools/tool_action_test.cc
+++ b/src/kudu/tools/tool_action_test.cc
@@ -105,6 +105,7 @@
#include "kudu/common/types.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/tools/tool_action_common.h"
#include "kudu/util/oid_generator.h"
#include "kudu/util/random.h"
#include "kudu/util/stopwatch.h"
@@ -204,11 +205,8 @@ DEFINE_bool(use_random, false,
namespace kudu {
namespace tools {
-
namespace {
-const char* const kMasterAddressesArg = "master_addresses";
-
class Generator {
public:
enum Mode {