tool: rename tablet mode to local_replica The tablet mode isn't actually going away, we're just going to use it for "remote operations that are scoped to an entire tablet".
Change-Id: I2022a49817bfa48b74c734fd849d92d1f15a697f Reviewed-on: http://gerrit.cloudera.org:8080/4355 Reviewed-by: Todd Lipcon <[email protected]> Tested-by: Kudu Jenkins Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/2e30b2a8 Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/2e30b2a8 Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/2e30b2a8 Branch: refs/heads/master Commit: 2e30b2a8fca48d472143a9782b2f2449dcd6cfc2 Parents: b5fc3a6 Author: Adar Dembo <[email protected]> Authored: Fri Sep 9 13:48:13 2016 -0700 Committer: Adar Dembo <[email protected]> Committed: Sat Sep 10 00:48:34 2016 +0000 ---------------------------------------------------------------------- docs/release_notes.adoc | 2 +- .../integration-tests/master_failover-itest.cc | 6 +- .../integration-tests/master_migration-itest.cc | 6 +- src/kudu/tools/CMakeLists.txt | 2 +- src/kudu/tools/kudu-tool-test.cc | 13 +- src/kudu/tools/tool_action.h | 2 +- src/kudu/tools/tool_action_local_replica.cc | 282 +++++++++++++++++++ src/kudu/tools/tool_action_tablet.cc | 282 ------------------- src/kudu/tools/tool_main.cc | 2 +- 9 files changed, 299 insertions(+), 298 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/docs/release_notes.adoc ---------------------------------------------------------------------- diff --git a/docs/release_notes.adoc b/docs/release_notes.adoc index 9a431fc..2388bce 100644 --- a/docs/release_notes.adoc +++ b/docs/release_notes.adoc @@ -59,7 +59,7 @@ Kudu 1.0.0 are not supported. implemented as `kudu fs cfile_dump`. - The `log-dump` tool has been removed. The same functionality is now - implemented as `kudu wal dump` and `kudu tablet dump_wals`. + implemented as `kudu wal dump` and `kudu local_replica dump_wals`. - KuduSession methods in the C++ library are no longer advertised as thread-safe to have one set of semantics for both C++ and Java Kudu client libraries. http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/src/kudu/integration-tests/master_failover-itest.cc ---------------------------------------------------------------------- diff --git a/src/kudu/integration-tests/master_failover-itest.cc b/src/kudu/integration-tests/master_failover-itest.cc index a2205c6..5063350 100644 --- a/src/kudu/integration-tests/master_failover-itest.cc +++ b/src/kudu/integration-tests/master_failover-itest.cc @@ -379,7 +379,7 @@ TEST_F(MasterFailoverTest, TestMasterPermanentFailure) { { vector<string> args = { kBinPath, - "tablet", + "local_replica", "cmeta", "print_replica_uuids", "--fs_wal_dir=" + other_master->data_dir(), @@ -419,8 +419,8 @@ TEST_F(MasterFailoverTest, TestMasterPermanentFailure) { { vector<string> args = { kBinPath, - "tablet", - "copy", + "local_replica", + "copy_from_remote", "--fs_wal_dir=" + data_root, "--fs_data_dirs=" + data_root, master::SysCatalogTable::kSysCatalogTabletId, http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/src/kudu/integration-tests/master_migration-itest.cc ---------------------------------------------------------------------- diff --git a/src/kudu/integration-tests/master_migration-itest.cc b/src/kudu/integration-tests/master_migration-itest.cc index ee9fb59..b01cda0 100644 --- a/src/kudu/integration-tests/master_migration-itest.cc +++ b/src/kudu/integration-tests/master_migration-itest.cc @@ -140,7 +140,7 @@ TEST_F(MasterMigrationTest, TestEndToEndMigration) { string data_root = cluster_->GetDataPath("master-0"); vector<string> args = { kBinPath, - "tablet", + "local_replica", "cmeta", "rewrite_raft_config", "--fs_wal_dir=" + data_root, @@ -168,8 +168,8 @@ TEST_F(MasterMigrationTest, TestEndToEndMigration) { string data_root = cluster_->GetDataPath(Substitute("master-$0", i)); vector<string> args = { kBinPath, - "tablet", - "copy", + "local_replica", + "copy_from_remote", "--fs_wal_dir=" + data_root, "--fs_data_dirs=" + data_root, SysCatalogTable::kSysCatalogTabletId, http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/src/kudu/tools/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/src/kudu/tools/CMakeLists.txt b/src/kudu/tools/CMakeLists.txt index c7c5a5f..9a029fb 100644 --- a/src/kudu/tools/CMakeLists.txt +++ b/src/kudu/tools/CMakeLists.txt @@ -89,8 +89,8 @@ add_executable(kudu tool_action_cluster.cc tool_action_common.cc tool_action_fs.cc + tool_action_local_replica.cc tool_action_pbc.cc - tool_action_tablet.cc tool_action_wal.cc tool_main.cc ) http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/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 b018f3b..89a0725 100644 --- a/src/kudu/tools/kudu-tool-test.cc +++ b/src/kudu/tools/kudu-tool-test.cc @@ -167,8 +167,8 @@ TEST_F(ToolTest, TestTopLevelHelp) { const vector<string> kTopLevelRegexes = { "cluster.*Kudu cluster", "fs.*Kudu filesystem", + "local_replica.*Kudu replicas", "pbc.*protobuf container", - "tablet.*Kudu replica", "wal.*write-ahead log" }; NO_FATALS(RunTestHelp("", kTopLevelRegexes)); @@ -188,19 +188,19 @@ TEST_F(ToolTest, TestModeHelp) { Status::InvalidArgument("unknown command 'not_a_mode'"))); } { - const vector<string> kTabletModeRegexes = { + const vector<string> kLocalReplicaModeRegexes = { "cmeta.*consensus metadata file", - "copy.*Copy a replica", + "copy_from_remote.*Copy a replica", "dump_wals.*Dump all WAL" }; - NO_FATALS(RunTestHelp("tablet", kTabletModeRegexes)); + NO_FATALS(RunTestHelp("local_replica", kLocalReplicaModeRegexes)); } { const vector<string> kCmetaModeRegexes = { "print_replica_uuids.*Print all replica UUIDs", "rewrite_raft_config.*Rewrite a replica" }; - NO_FATALS(RunTestHelp("tablet cmeta", kCmetaModeRegexes)); + NO_FATALS(RunTestHelp("local_replica cmeta", kCmetaModeRegexes)); } { const vector<string> kClusterModeRegexes = { @@ -404,7 +404,8 @@ TEST_F(ToolTest, TestWalDump) { string wal_path = fs.GetWalSegmentFileName(kTestTablet, 1); string stdout; for (const auto& args : { Substitute("wal dump $0", wal_path), - Substitute("tablet dump_wals --fs_wal_dir=$0 $1", kTestDir, kTestTablet) + Substitute("local_replica dump_wals --fs_wal_dir=$0 $1", + kTestDir, kTestTablet) }) { SCOPED_TRACE(args); for (const auto& print_entries : { "true", "1", "yes", "decoded" }) { http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/src/kudu/tools/tool_action.h ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_action.h b/src/kudu/tools/tool_action.h index e8bdc90..1730a1d 100644 --- a/src/kudu/tools/tool_action.h +++ b/src/kudu/tools/tool_action.h @@ -274,8 +274,8 @@ class Action { // Returns new nodes for each major mode. std::unique_ptr<Mode> BuildClusterMode(); std::unique_ptr<Mode> BuildFsMode(); +std::unique_ptr<Mode> BuildLocalReplicaMode(); std::unique_ptr<Mode> BuildPbcMode(); -std::unique_ptr<Mode> BuildTabletMode(); std::unique_ptr<Mode> BuildWalMode(); } // namespace tools http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/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 new file mode 100644 index 0000000..17aecaf --- /dev/null +++ b/src/kudu/tools/tool_action_local_replica.cc @@ -0,0 +1,282 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "kudu/tools/tool_action.h" + +#include <iostream> +#include <list> +#include <memory> +#include <string> +#include <utility> + +#include "kudu/common/wire_protocol.h" +#include "kudu/consensus/consensus_meta.h" +#include "kudu/consensus/log_index.h" +#include "kudu/consensus/log_reader.h" +#include "kudu/consensus/log_util.h" +#include "kudu/fs/fs_manager.h" +#include "kudu/gutil/map-util.h" +#include "kudu/gutil/ref_counted.h" +#include "kudu/gutil/strings/join.h" +#include "kudu/gutil/strings/split.h" +#include "kudu/gutil/strings/stringpiece.h" +#include "kudu/gutil/strings/substitute.h" +#include "kudu/master/sys_catalog.h" +#include "kudu/rpc/messenger.h" +#include "kudu/tools/tool_action_common.h" +#include "kudu/tserver/tablet_copy_client.h" +#include "kudu/util/env.h" +#include "kudu/util/env_util.h" +#include "kudu/util/metrics.h" +#include "kudu/util/net/net_util.h" +#include "kudu/util/status.h" + +namespace kudu { +namespace tools { + +using consensus::ConsensusMetadata; +using consensus::RaftConfigPB; +using consensus::RaftPeerPB; +using log::LogIndex; +using log::LogReader; +using log::ReadableLogSegment; +using log::SegmentSequence; +using rpc::Messenger; +using rpc::MessengerBuilder; +using std::cout; +using std::endl; +using std::list; +using std::shared_ptr; +using std::string; +using std::unique_ptr; +using std::vector; +using strings::Split; +using strings::Substitute; +using tserver::TabletCopyClient; + +namespace { + +// Parses a colon-delimited string containing a hostname or IP address and port +// into its respective parts. For example, "localhost:12345" parses into +// hostname=localhost, and port=12345. +// +// Does not allow a port with value 0. +Status ParseHostPortString(const string& hostport_str, HostPort* hostport) { + HostPort hp; + Status s = hp.ParseString(hostport_str, 0); + if (!s.ok()) { + return s.CloneAndPrepend(Substitute( + "error while parsing peer '$0'", hostport_str)); + } + if (hp.port() == 0) { + return Status::InvalidArgument( + Substitute("peer '$0' has port of 0", hostport_str)); + } + *hostport = hp; + return Status::OK(); +} + +// Parses a colon-delimited string containing a uuid, hostname or IP address, +// and port into its respective parts. For example, +// "1c7f19e7ecad4f918c0d3d23180fdb18:localhost:12345" parses into +// uuid=1c7f19e7ecad4f918c0d3d23180fdb18, hostname=localhost, and port=12345. +Status ParsePeerString(const string& peer_str, + string* uuid, + HostPort* hostport) { + string::size_type first_colon_idx = peer_str.find(":"); + if (first_colon_idx == string::npos) { + return Status::InvalidArgument(Substitute("bad peer '$0'", peer_str)); + } + string hostport_str = peer_str.substr(first_colon_idx + 1); + RETURN_NOT_OK(ParseHostPortString(hostport_str, hostport)); + *uuid = peer_str.substr(0, first_colon_idx); + return Status::OK(); +} + +Status PrintReplicaUuids(const RunnerContext& context) { + string tablet_id = FindOrDie(context.required_args, "tablet_id"); + + FsManagerOpts opts; + opts.read_only = true; + FsManager fs_manager(Env::Default(), opts); + RETURN_NOT_OK(fs_manager.Open()); + + // Load the cmeta file and print all peer uuids. + unique_ptr<ConsensusMetadata> cmeta; + RETURN_NOT_OK(ConsensusMetadata::Load(&fs_manager, tablet_id, + fs_manager.uuid(), &cmeta)); + cout << JoinMapped(cmeta->committed_config().peers(), + [](const RaftPeerPB& p){ return p.permanent_uuid(); }, + " ") << endl; + return Status::OK(); +} + +Status RewriteRaftConfig(const RunnerContext& context) { + // Parse tablet ID argument. + string tablet_id = FindOrDie(context.required_args, "tablet_id"); + 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."; + } + + // Parse peer arguments. + vector<pair<string, HostPort>> peers; + for (const auto& arg : context.variadic_args) { + pair<string, HostPort> parsed_peer; + RETURN_NOT_OK(ParsePeerString(arg, + &parsed_peer.first, &parsed_peer.second)); + peers.push_back(parsed_peer); + } + DCHECK(!peers.empty()); + + // Make a copy of the old file before rewriting it. + Env* env = Env::Default(); + FsManager fs_manager(env, FsManagerOpts()); + RETURN_NOT_OK(fs_manager.Open()); + string cmeta_filename = fs_manager.GetConsensusMetadataPath(tablet_id); + string backup_filename = Substitute("$0.pre_rewrite.$1", + cmeta_filename, env->NowMicros()); + WritableFileOptions opts; + opts.mode = Env::CREATE_NON_EXISTING; + opts.sync_on_close = true; + RETURN_NOT_OK(env_util::CopyFile(env, cmeta_filename, backup_filename, opts)); + LOG(INFO) << "Backed up current config to " << backup_filename; + + // Load the cmeta file and rewrite the raft config. + unique_ptr<ConsensusMetadata> cmeta; + RETURN_NOT_OK(ConsensusMetadata::Load(&fs_manager, tablet_id, + fs_manager.uuid(), &cmeta)); + RaftConfigPB current_config = cmeta->committed_config(); + RaftConfigPB new_config = current_config; + new_config.clear_peers(); + for (const auto& p : peers) { + RaftPeerPB new_peer; + new_peer.set_member_type(RaftPeerPB::VOTER); + new_peer.set_permanent_uuid(p.first); + HostPortPB new_peer_host_port_pb; + RETURN_NOT_OK(HostPortToPB(p.second, &new_peer_host_port_pb)); + new_peer.mutable_last_known_addr()->CopyFrom(new_peer_host_port_pb); + new_config.add_peers()->CopyFrom(new_peer); + } + cmeta->set_committed_config(new_config); + return cmeta->Flush(); +} + +Status CopyFromRemote(const RunnerContext& context) { + // Parse the tablet ID and source arguments. + string tablet_id = FindOrDie(context.required_args, "tablet_id"); + string rpc_address = FindOrDie(context.required_args, "source"); + + HostPort hp; + RETURN_NOT_OK(ParseHostPortString(rpc_address, &hp)); + + // Copy the tablet over. + FsManager fs_manager(Env::Default(), FsManagerOpts()); + RETURN_NOT_OK(fs_manager.Open()); + MessengerBuilder builder("tablet_copy_client"); + shared_ptr<Messenger> messenger; + builder.Build(&messenger); + TabletCopyClient client(tablet_id, &fs_manager, messenger); + RETURN_NOT_OK(client.Start(hp, nullptr)); + RETURN_NOT_OK(client.FetchAll(nullptr)); + return client.Finish(); +} + +Status DumpWals(const RunnerContext& context) { + string tablet_id = FindOrDie(context.required_args, "tablet_id"); + + FsManagerOpts fs_opts; + fs_opts.read_only = true; + FsManager fs_manager(Env::Default(), fs_opts); + RETURN_NOT_OK(fs_manager.Open()); + + shared_ptr<LogReader> reader; + RETURN_NOT_OK(LogReader::Open(&fs_manager, + scoped_refptr<LogIndex>(), + tablet_id, + scoped_refptr<MetricEntity>(), + &reader)); + + SegmentSequence segments; + RETURN_NOT_OK(reader->GetSegmentsSnapshot(&segments)); + + for (const scoped_refptr<ReadableLogSegment>& segment : segments) { + RETURN_NOT_OK(PrintSegment(segment)); + } + + return Status::OK(); +} + +} // anonymous namespace + +unique_ptr<Mode> BuildLocalReplicaMode() { + unique_ptr<Action> print_replica_uuids = + ActionBuilder("print_replica_uuids", &PrintReplicaUuids) + .Description("Print all replica UUIDs found in a tablet's Raft configuration") + .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) + .AddOptionalParameter("fs_wal_dir") + .AddOptionalParameter("fs_data_dirs") + .Build(); + + unique_ptr<Action> rewrite_raft_config = + ActionBuilder("rewrite_raft_config", &RewriteRaftConfig) + .Description("Rewrite a replica's Raft configuration") + .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) + .AddRequiredVariadicParameter({ + "peers", "List of peers where each peer is of form uuid:hostname:port" }) + .AddOptionalParameter("fs_wal_dir") + .AddOptionalParameter("fs_data_dirs") + .Build(); + + unique_ptr<Mode> cmeta = + ModeBuilder("cmeta") + .Description("Operate on a local Kudu tablet's consensus metadata file") + .AddAction(std::move(print_replica_uuids)) + .AddAction(std::move(rewrite_raft_config)) + .Build(); + + 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({ "source", "Source RPC address of form hostname:port" }) + .AddOptionalParameter("fs_wal_dir") + .AddOptionalParameter("fs_data_dirs") + .Build(); + + unique_ptr<Action> dump_wals = + ActionBuilder("dump_wals", &DumpWals) + .Description("Dump all WAL (write-ahead log) segments of a tablet") + .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) + .AddOptionalParameter("fs_wal_dir") + .AddOptionalParameter("fs_data_dirs") + .AddOptionalParameter("print_entries") + .AddOptionalParameter("print_meta") + .AddOptionalParameter("truncate_data") + .Build(); + + return ModeBuilder("local_replica") + .Description("Operate on local Kudu replicas via the local filesystem") + .AddMode(std::move(cmeta)) + .AddAction(std::move(copy_from_remote)) + .AddAction(std::move(dump_wals)) + .Build(); +} + +} // namespace tools +} // namespace kudu + http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/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 deleted file mode 100644 index 736c2e5..0000000 --- a/src/kudu/tools/tool_action_tablet.cc +++ /dev/null @@ -1,282 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "kudu/tools/tool_action.h" - -#include <iostream> -#include <list> -#include <memory> -#include <string> -#include <utility> - -#include "kudu/common/wire_protocol.h" -#include "kudu/consensus/consensus_meta.h" -#include "kudu/consensus/log_index.h" -#include "kudu/consensus/log_reader.h" -#include "kudu/consensus/log_util.h" -#include "kudu/fs/fs_manager.h" -#include "kudu/gutil/map-util.h" -#include "kudu/gutil/ref_counted.h" -#include "kudu/gutil/strings/join.h" -#include "kudu/gutil/strings/split.h" -#include "kudu/gutil/strings/stringpiece.h" -#include "kudu/gutil/strings/substitute.h" -#include "kudu/master/sys_catalog.h" -#include "kudu/rpc/messenger.h" -#include "kudu/tools/tool_action_common.h" -#include "kudu/tserver/tablet_copy_client.h" -#include "kudu/util/env.h" -#include "kudu/util/env_util.h" -#include "kudu/util/metrics.h" -#include "kudu/util/net/net_util.h" -#include "kudu/util/status.h" - -namespace kudu { -namespace tools { - -using consensus::ConsensusMetadata; -using consensus::RaftConfigPB; -using consensus::RaftPeerPB; -using log::LogIndex; -using log::LogReader; -using log::ReadableLogSegment; -using log::SegmentSequence; -using rpc::Messenger; -using rpc::MessengerBuilder; -using std::cout; -using std::endl; -using std::list; -using std::shared_ptr; -using std::string; -using std::unique_ptr; -using std::vector; -using strings::Split; -using strings::Substitute; -using tserver::TabletCopyClient; - -namespace { - -// Parses a colon-delimited string containing a hostname or IP address and port -// into its respective parts. For example, "localhost:12345" parses into -// hostname=localhost, and port=12345. -// -// Does not allow a port with value 0. -Status ParseHostPortString(const string& hostport_str, HostPort* hostport) { - HostPort hp; - Status s = hp.ParseString(hostport_str, 0); - if (!s.ok()) { - return s.CloneAndPrepend(Substitute( - "error while parsing peer '$0'", hostport_str)); - } - if (hp.port() == 0) { - return Status::InvalidArgument( - Substitute("peer '$0' has port of 0", hostport_str)); - } - *hostport = hp; - return Status::OK(); -} - -// Parses a colon-delimited string containing a uuid, hostname or IP address, -// and port into its respective parts. For example, -// "1c7f19e7ecad4f918c0d3d23180fdb18:localhost:12345" parses into -// uuid=1c7f19e7ecad4f918c0d3d23180fdb18, hostname=localhost, and port=12345. -Status ParsePeerString(const string& peer_str, - string* uuid, - HostPort* hostport) { - string::size_type first_colon_idx = peer_str.find(":"); - if (first_colon_idx == string::npos) { - return Status::InvalidArgument(Substitute("bad peer '$0'", peer_str)); - } - string hostport_str = peer_str.substr(first_colon_idx + 1); - RETURN_NOT_OK(ParseHostPortString(hostport_str, hostport)); - *uuid = peer_str.substr(0, first_colon_idx); - return Status::OK(); -} - -Status PrintReplicaUuids(const RunnerContext& context) { - string tablet_id = FindOrDie(context.required_args, "tablet_id"); - - FsManagerOpts opts; - opts.read_only = true; - FsManager fs_manager(Env::Default(), opts); - RETURN_NOT_OK(fs_manager.Open()); - - // Load the cmeta file and print all peer uuids. - unique_ptr<ConsensusMetadata> cmeta; - RETURN_NOT_OK(ConsensusMetadata::Load(&fs_manager, tablet_id, - fs_manager.uuid(), &cmeta)); - cout << JoinMapped(cmeta->committed_config().peers(), - [](const RaftPeerPB& p){ return p.permanent_uuid(); }, - " ") << endl; - return Status::OK(); -} - -Status RewriteRaftConfig(const RunnerContext& context) { - // Parse tablet ID argument. - string tablet_id = FindOrDie(context.required_args, "tablet_id"); - 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."; - } - - // Parse peer arguments. - vector<pair<string, HostPort>> peers; - for (const auto& arg : context.variadic_args) { - pair<string, HostPort> parsed_peer; - RETURN_NOT_OK(ParsePeerString(arg, - &parsed_peer.first, &parsed_peer.second)); - peers.push_back(parsed_peer); - } - DCHECK(!peers.empty()); - - // Make a copy of the old file before rewriting it. - Env* env = Env::Default(); - FsManager fs_manager(env, FsManagerOpts()); - RETURN_NOT_OK(fs_manager.Open()); - string cmeta_filename = fs_manager.GetConsensusMetadataPath(tablet_id); - string backup_filename = Substitute("$0.pre_rewrite.$1", - cmeta_filename, env->NowMicros()); - WritableFileOptions opts; - opts.mode = Env::CREATE_NON_EXISTING; - opts.sync_on_close = true; - RETURN_NOT_OK(env_util::CopyFile(env, cmeta_filename, backup_filename, opts)); - LOG(INFO) << "Backed up current config to " << backup_filename; - - // Load the cmeta file and rewrite the raft config. - unique_ptr<ConsensusMetadata> cmeta; - RETURN_NOT_OK(ConsensusMetadata::Load(&fs_manager, tablet_id, - fs_manager.uuid(), &cmeta)); - RaftConfigPB current_config = cmeta->committed_config(); - RaftConfigPB new_config = current_config; - new_config.clear_peers(); - for (const auto& p : peers) { - RaftPeerPB new_peer; - new_peer.set_member_type(RaftPeerPB::VOTER); - new_peer.set_permanent_uuid(p.first); - HostPortPB new_peer_host_port_pb; - RETURN_NOT_OK(HostPortToPB(p.second, &new_peer_host_port_pb)); - new_peer.mutable_last_known_addr()->CopyFrom(new_peer_host_port_pb); - new_config.add_peers()->CopyFrom(new_peer); - } - cmeta->set_committed_config(new_config); - return cmeta->Flush(); -} - -Status Copy(const RunnerContext& context) { - // Parse the tablet ID and source arguments. - string tablet_id = FindOrDie(context.required_args, "tablet_id"); - string rpc_address = FindOrDie(context.required_args, "source"); - - HostPort hp; - RETURN_NOT_OK(ParseHostPortString(rpc_address, &hp)); - - // Copy the tablet over. - FsManager fs_manager(Env::Default(), FsManagerOpts()); - RETURN_NOT_OK(fs_manager.Open()); - MessengerBuilder builder("tablet_copy_client"); - shared_ptr<Messenger> messenger; - builder.Build(&messenger); - TabletCopyClient client(tablet_id, &fs_manager, messenger); - RETURN_NOT_OK(client.Start(hp, nullptr)); - RETURN_NOT_OK(client.FetchAll(nullptr)); - return client.Finish(); -} - -Status DumpWals(const RunnerContext& context) { - string tablet_id = FindOrDie(context.required_args, "tablet_id"); - - FsManagerOpts fs_opts; - fs_opts.read_only = true; - FsManager fs_manager(Env::Default(), fs_opts); - RETURN_NOT_OK(fs_manager.Open()); - - shared_ptr<LogReader> reader; - RETURN_NOT_OK(LogReader::Open(&fs_manager, - scoped_refptr<LogIndex>(), - tablet_id, - scoped_refptr<MetricEntity>(), - &reader)); - - SegmentSequence segments; - RETURN_NOT_OK(reader->GetSegmentsSnapshot(&segments)); - - for (const scoped_refptr<ReadableLogSegment>& segment : segments) { - RETURN_NOT_OK(PrintSegment(segment)); - } - - return Status::OK(); -} - -} // anonymous namespace - -unique_ptr<Mode> BuildTabletMode() { - unique_ptr<Action> print_replica_uuids = - ActionBuilder("print_replica_uuids", &PrintReplicaUuids) - .Description("Print all replica UUIDs found in a tablet's Raft configuration") - .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) - .AddOptionalParameter("fs_wal_dir") - .AddOptionalParameter("fs_data_dirs") - .Build(); - - unique_ptr<Action> rewrite_raft_config = - ActionBuilder("rewrite_raft_config", &RewriteRaftConfig) - .Description("Rewrite a replica's Raft configuration") - .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) - .AddRequiredVariadicParameter({ - "peers", "List of peers where each peer is of form uuid:hostname:port" }) - .AddOptionalParameter("fs_wal_dir") - .AddOptionalParameter("fs_data_dirs") - .Build(); - - unique_ptr<Mode> cmeta = - ModeBuilder("cmeta") - .Description("Operate on a local Kudu tablet's consensus metadata file") - .AddAction(std::move(print_replica_uuids)) - .AddAction(std::move(rewrite_raft_config)) - .Build(); - - unique_ptr<Action> copy = - ActionBuilder("copy", &Copy) - .Description("Copy a replica from a remote server") - .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) - .AddRequiredParameter({ "source", "Source RPC address of form hostname:port" }) - .AddOptionalParameter("fs_wal_dir") - .AddOptionalParameter("fs_data_dirs") - .Build(); - - unique_ptr<Action> dump_wals = - ActionBuilder("dump_wals", &DumpWals) - .Description("Dump all WAL (write-ahead log) segments of a tablet") - .AddRequiredParameter({ "tablet_id", "Tablet identifier" }) - .AddOptionalParameter("fs_wal_dir") - .AddOptionalParameter("fs_data_dirs") - .AddOptionalParameter("print_entries") - .AddOptionalParameter("print_meta") - .AddOptionalParameter("truncate_data") - .Build(); - - return ModeBuilder("tablet") - .Description("Operate on a local Kudu replica") - .AddMode(std::move(cmeta)) - .AddAction(std::move(copy)) - .AddAction(std::move(dump_wals)) - .Build(); -} - -} // namespace tools -} // namespace kudu - http://git-wip-us.apache.org/repos/asf/kudu/blob/2e30b2a8/src/kudu/tools/tool_main.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_main.cc b/src/kudu/tools/tool_main.cc index f1fbe93..c18065d 100644 --- a/src/kudu/tools/tool_main.cc +++ b/src/kudu/tools/tool_main.cc @@ -113,8 +113,8 @@ int RunTool(int argc, char** argv, bool show_help) { .Description("doesn't matter") // root mode description isn't printed .AddMode(BuildClusterMode()) .AddMode(BuildFsMode()) + .AddMode(BuildLocalReplicaMode()) .AddMode(BuildPbcMode()) - .AddMode(BuildTabletMode()) .AddMode(BuildWalMode()) .Build();
