You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2016/09/13 02:18:27 UTC
[1/3] kudu git commit: Remove a spurious warning left in
raft_consensus_state.cc
Repository: kudu
Updated Branches:
refs/heads/master 2628ec0d7 -> 14cd22a10
Remove a spurious warning left in raft_consensus_state.cc
Change-Id: I0bcada22bc31e1640e5e047c2326f61dc617705d
Reviewed-on: http://gerrit.cloudera.org:8080/4391
Reviewed-by: Mike Percy <mp...@apache.org>
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/b150c052
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/b150c052
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/b150c052
Branch: refs/heads/master
Commit: b150c052a8c663cbc5bcfcc3b8fa5fe26c900fb2
Parents: 2628ec0
Author: Todd Lipcon <to...@apache.org>
Authored: Mon Sep 12 17:53:07 2016 -0700
Committer: Todd Lipcon <to...@apache.org>
Committed: Tue Sep 13 01:24:08 2016 +0000
----------------------------------------------------------------------
src/kudu/consensus/raft_consensus_state.cc | 1 -
1 file changed, 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/b150c052/src/kudu/consensus/raft_consensus_state.cc
----------------------------------------------------------------------
diff --git a/src/kudu/consensus/raft_consensus_state.cc b/src/kudu/consensus/raft_consensus_state.cc
index 7631f26..394d6e5 100644
--- a/src/kudu/consensus/raft_consensus_state.cc
+++ b/src/kudu/consensus/raft_consensus_state.cc
@@ -586,7 +586,6 @@ Status ReplicaState::SetInitialCommittedOpIdUnlocked(const OpId& committed_op) {
} else {
last_committed_op_id_ = committed_op;
- LOG_WITH_PREFIX_UNLOCKED(WARNING) << "setting committed at start to " << committed_op;
}
return Status::OK();
}
[2/3] kudu git commit: tool: port kudu-fs_dump, remove kudu-fs_list,
fs_tool
Posted by to...@apache.org.
tool: port kudu-fs_dump, remove kudu-fs_list, fs_tool
This change ports fs_dump actions under 'kudu local_replica '.
Additionally this has following re-organizations:
- moved dump_cfile action under 'kudu fs dump cfile'.
- kudu-fs_list tool has been removed altogether,
but some of the functionalities are retained under
'local_replica' and 'fs dump' sub-actions.
- fs_tool library is stripped off, and all those
routines are in respective action files.
Also added tests under kudu-tool-test to exercise each of these fs tools.
Change-Id: I1ec628b65613011d8c48b6239c13762276425966
Reviewed-on: http://gerrit.cloudera.org:8080/4305
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/9cb1bcac
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/9cb1bcac
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/9cb1bcac
Branch: refs/heads/master
Commit: 9cb1bcacf1449a41ebd6a2c13faead2665ea38f9
Parents: b150c05
Author: Dinesh Bhat <di...@cloudera.com>
Authored: Tue Aug 30 12:14:46 2016 -0700
Committer: Todd Lipcon <to...@apache.org>
Committed: Tue Sep 13 02:14:23 2016 +0000
----------------------------------------------------------------------
docs/release_notes.adoc | 10 +-
.../integration-tests/master_migration-itest.cc | 3 +-
src/kudu/tablet/rowset_metadata.h | 9 +-
src/kudu/tools/CMakeLists.txt | 20 +-
src/kudu/tools/fs_tool.cc | 576 -------------------
src/kudu/tools/fs_tool.h | 158 -----
src/kudu/tools/kudu-tool-test.cc | 240 +++++++-
src/kudu/tools/tool_action.h | 9 +-
src/kudu/tools/tool_action_fs.cc | 64 ++-
src/kudu/tools/tool_action_local_replica.cc | 493 +++++++++++++++-
src/kudu/tools/tool_action_tablet.cc | 1 -
11 files changed, 763 insertions(+), 820 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/docs/release_notes.adoc
----------------------------------------------------------------------
diff --git a/docs/release_notes.adoc b/docs/release_notes.adoc
index 3034b34..9fd83ef 100644
--- a/docs/release_notes.adoc
+++ b/docs/release_notes.adoc
@@ -119,14 +119,20 @@ Kudu 1.0.0 are not supported.
implemented as `kudu cluster ksck`.
- The `cfile-dump` tool has been removed. The same functionality is now
- implemented as `kudu fs cfile_dump`.
+ 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 local_replica dump_wals`.
+ implemented as `kudu wal dump` and `kudu local_replica dump wals`.
- The `kudu-admin` tool has been removed. The same functionality is now
implemented within `kudu table` and `kudu tablet`.
+- The `kudu-fs_dump` tool has been removed. The same functionality is now
+ implemented as `kudu fs dump`.
+
+- The `kudu-fs_list` tool has been removed and some similar useful
+ functionality has been moved under 'kudu local_replica'.
+
=== Configuration flags
- Some configuration flags are now marked as 'unsafe' and 'experimental'. Such flags
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/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 b01cda0..c1d66e2 100644
--- a/src/kudu/integration-tests/master_migration-itest.cc
+++ b/src/kudu/integration-tests/master_migration-itest.cc
@@ -124,7 +124,8 @@ TEST_F(MasterMigrationTest, TestEndToEndMigration) {
vector<string> args = {
kBinPath,
"fs",
- "print_uuid",
+ "dump",
+ "uuid",
"--fs_wal_dir=" + data_root,
"--fs_data_dirs=" + data_root
};
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tablet/rowset_metadata.h
----------------------------------------------------------------------
diff --git a/src/kudu/tablet/rowset_metadata.h b/src/kudu/tablet/rowset_metadata.h
index c195d8f..8813602 100644
--- a/src/kudu/tablet/rowset_metadata.h
+++ b/src/kudu/tablet/rowset_metadata.h
@@ -34,10 +34,6 @@
namespace kudu {
-namespace tools {
-class FsTool;
-} // namespace tools
-
namespace tablet {
class RowSetMetadataUpdate;
@@ -173,11 +169,12 @@ class RowSetMetadata {
// On success, calls TabletMetadata::AddOrphanedBlocks() on the removed blocks.
Status CommitUpdate(const RowSetMetadataUpdate& update);
+ void ToProtobuf(RowSetDataPB *pb);
+
std::vector<BlockId> GetAllBlocks();
private:
friend class TabletMetadata;
- friend class kudu::tools::FsTool;
typedef simple_spinlock LockType;
@@ -197,8 +194,6 @@ class RowSetMetadata {
Status InitFromPB(const RowSetDataPB& pb);
- void ToProtobuf(RowSetDataPB *pb);
-
TabletMetadata* const tablet_metadata_;
bool initted_;
int64_t id_;
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tools/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/tools/CMakeLists.txt b/src/kudu/tools/CMakeLists.txt
index 8a707bf..0ce2899 100644
--- a/src/kudu/tools/CMakeLists.txt
+++ b/src/kudu/tools/CMakeLists.txt
@@ -48,24 +48,6 @@ add_executable(kudu-ts-cli ts-cli.cc)
target_link_libraries(kudu-ts-cli
${LINK_LIBS})
-add_library(fs_tool fs_tool.cc)
-target_link_libraries(fs_tool
- gutil
- kudu_common
- server_common
- consensus
- tablet)
-
-add_executable(kudu-fs_list fs_list-tool.cc)
-target_link_libraries(kudu-fs_list
- ${LINK_LIBS}
- fs_tool)
-
-add_executable(kudu-fs_dump fs_dump-tool.cc)
-target_link_libraries(kudu-fs_dump
- ${LINK_LIBS}
- fs_tool)
-
add_library(ksck
ksck.cc
ksck_remote.cc
@@ -102,6 +84,8 @@ target_link_libraries(kudu
kudu_util
log
master
+ server_common
+ tablet
tserver
${KUDU_BASE_LIBS}
)
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tools/fs_tool.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/fs_tool.cc b/src/kudu/tools/fs_tool.cc
deleted file mode 100644
index 960a82b..0000000
--- a/src/kudu/tools/fs_tool.cc
+++ /dev/null
@@ -1,576 +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/fs_tool.h"
-
-#include <algorithm>
-#include <iostream>
-#include <memory>
-#include <vector>
-
-#include <boost/function.hpp>
-#include <gflags/gflags.h>
-#include <glog/logging.h>
-
-#include "kudu/cfile/cfile_reader.h"
-#include "kudu/common/rowblock.h"
-#include "kudu/common/row_changelist.h"
-#include "kudu/consensus/log_util.h"
-#include "kudu/consensus/log_reader.h"
-#include "kudu/fs/fs_manager.h"
-#include "kudu/gutil/strings/human_readable.h"
-#include "kudu/gutil/strings/substitute.h"
-#include "kudu/gutil/strings/util.h"
-#include "kudu/tablet/cfile_set.h"
-#include "kudu/tablet/deltafile.h"
-#include "kudu/tablet/tablet.h"
-#include "kudu/util/env.h"
-#include "kudu/util/logging.h"
-#include "kudu/util/mem_tracker.h"
-#include "kudu/util/memory/arena.h"
-#include "kudu/util/status.h"
-
-namespace kudu {
-namespace tools {
-
-using cfile::CFileIterator;
-using cfile::CFileReader;
-using cfile::DumpIterator;
-using cfile::ReaderOptions;
-using fs::ReadableBlock;
-using log::LogReader;
-using log::ReadableLogSegment;
-using std::shared_ptr;
-using std::string;
-using std::vector;
-using strings::Substitute;
-using tablet::CFileSet;
-using tablet::DeltaFileReader;
-using tablet::DeltaIterator;
-using tablet::DeltaKeyAndUpdate;
-using tablet::DeltaType;
-using tablet::MvccSnapshot;
-using tablet::RowSetMetadata;
-using tablet::Tablet;
-using tablet::TabletMetadata;
-
-static const char* const kSeparatorLine =
- "----------------------------------------------------------------------\n";
-
-namespace {
-string Indent(int indent) {
- return string(indent, ' ');
-}
-
-string IndentString(const string& s, int indent) {
- return Indent(indent) + StringReplace(s, "\n", "\n" + Indent(indent), true);
-}
-} // anonymous namespace
-
-FsTool::FsTool(DetailLevel detail_level)
- : initialized_(false),
- detail_level_(detail_level) {
-}
-
-FsTool::~FsTool() {
-}
-
-Status FsTool::Init() {
- CHECK(!initialized_) << "Already initialized";
- // Allow read-only access to live blocks.
- FsManagerOpts opts;
- opts.read_only = true;
- fs_manager_.reset(new FsManager(Env::Default(), opts));
- RETURN_NOT_OK(fs_manager_->Open());
-
- LOG(INFO) << "Opened file system with uuid: " << fs_manager_->uuid();
-
- initialized_ = true;
- return Status::OK();
-}
-
-Status FsTool::FsTree() {
- DCHECK(initialized_);
-
- fs_manager_->DumpFileSystemTree(std::cout);
- return Status::OK();
-}
-
-Status FsTool::ListAllLogSegments() {
- DCHECK(initialized_);
-
- string wals_dir = fs_manager_->GetWalsRootDir();
- if (!fs_manager_->Exists(wals_dir)) {
- return Status::Corruption(Substitute(
- "root log directory '$0' does not exist", wals_dir));
- }
-
- std::cout << "Root log directory: " << wals_dir << std::endl;
-
- vector<string> children;
- RETURN_NOT_OK_PREPEND(fs_manager_->ListDir(wals_dir, &children),
- "Could not list log directories");
- for (const string& child : children) {
- if (HasPrefixString(child, ".")) {
- // Hidden files or ./..
- VLOG(1) << "Ignoring hidden file in root log directory " << child;
- continue;
- }
- string path = JoinPathSegments(wals_dir, child);
- if (HasSuffixString(child, FsManager::kWalsRecoveryDirSuffix)) {
- std::cout << "Log recovery dir found: " << path << std::endl;
- } else {
- std::cout << "Log directory: " << path << std::endl;
- }
- RETURN_NOT_OK(ListSegmentsInDir(path));
- }
- return Status::OK();
-}
-
-Status FsTool::ListLogSegmentsForTablet(const string& tablet_id) {
- DCHECK(initialized_);
-
- string tablet_wal_dir = fs_manager_->GetTabletWalDir(tablet_id);
- if (!fs_manager_->Exists(tablet_wal_dir)) {
- return Status::NotFound(Substitute("tablet '$0' has no logs in wals dir '$1'",
- tablet_id, tablet_wal_dir));
- }
- std::cout << "Tablet WAL dir found: " << tablet_wal_dir << std::endl;
- RETURN_NOT_OK(ListSegmentsInDir(tablet_wal_dir));
- string recovery_dir = fs_manager_->GetTabletWalRecoveryDir(tablet_id);
- if (fs_manager_->Exists(recovery_dir)) {
- std::cout << "Recovery dir found: " << recovery_dir << std::endl;
- RETURN_NOT_OK(ListSegmentsInDir(recovery_dir));
- }
- return Status::OK();
-}
-
-
-Status FsTool::ListAllTablets() {
- DCHECK(initialized_);
-
- vector<string> tablets;
- RETURN_NOT_OK(fs_manager_->ListTabletIds(&tablets));
- for (const string& tablet : tablets) {
- if (detail_level_ >= HEADERS_ONLY) {
- std::cout << "Tablet: " << tablet << std::endl;
- RETURN_NOT_OK(PrintTabletMeta(tablet, 2));
- } else {
- std::cout << "\t" << tablet << std::endl;
- }
- }
- return Status::OK();
-}
-
-Status FsTool::ListSegmentsInDir(const string& segments_dir) {
- vector<string> segments;
- RETURN_NOT_OK_PREPEND(fs_manager_->ListDir(segments_dir, &segments),
- "Unable to list log segments");
- std::cout << "Segments in " << segments_dir << ":" << std::endl;
- for (const string& segment : segments) {
- if (!log::IsLogFileName(segment)) {
- continue;
- }
- if (detail_level_ >= HEADERS_ONLY) {
- std::cout << "Segment: " << segment << std::endl;
- string path = JoinPathSegments(segments_dir, segment);
- RETURN_NOT_OK(PrintLogSegmentHeader(path, 2));
- } else {
- std::cout << "\t" << segment << std::endl;
- }
- }
- return Status::OK();
-}
-
-Status FsTool::PrintLogSegmentHeader(const string& path,
- int indent) {
- scoped_refptr<ReadableLogSegment> segment;
- Status s = ReadableLogSegment::Open(fs_manager_->env(),
- path,
- &segment);
-
- if (s.IsUninitialized()) {
- LOG(ERROR) << path << " is not initialized: " << s.ToString();
- return Status::OK();
- }
- if (s.IsCorruption()) {
- LOG(ERROR) << path << " is corrupt: " << s.ToString();
- return Status::OK();
- }
- RETURN_NOT_OK_PREPEND(s, "Unexpected error reading log segment " + path);
-
- std::cout << Indent(indent) << "Size: "
- << HumanReadableNumBytes::ToStringWithoutRounding(segment->file_size())
- << std::endl;
- std::cout << Indent(indent) << "Header: " << std::endl;
- std::cout << IndentString(segment->header().DebugString(), indent);
- return Status::OK();
-}
-
-Status FsTool::PrintTabletMeta(const string& tablet_id, int indent) {
- scoped_refptr<TabletMetadata> meta;
- RETURN_NOT_OK(TabletMetadata::Load(fs_manager_.get(), tablet_id, &meta));
-
- const Schema& schema = meta->schema();
-
- std::cout << Indent(indent) << "Partition: "
- << meta->partition_schema().PartitionDebugString(meta->partition(), meta->schema())
- << std::endl;
- std::cout << Indent(indent) << "Table name: " << meta->table_name()
- << " Table id: " << meta->table_id() << std::endl;
- std::cout << Indent(indent) << "Schema (version=" << meta->schema_version() << "): "
- << schema.ToString() << std::endl;
-
- tablet::TabletSuperBlockPB pb;
- RETURN_NOT_OK_PREPEND(meta->ToSuperBlock(&pb), "Could not get superblock");
- std::cout << "Superblock:\n" << pb.DebugString() << std::endl;
-
- return Status::OK();
-}
-
-Status FsTool::ListBlocksForAllTablets() {
- DCHECK(initialized_);
-
- vector<string> tablets;
- RETURN_NOT_OK(fs_manager_->ListTabletIds(&tablets));
- for (string tablet : tablets) {
- RETURN_NOT_OK(ListBlocksForTablet(tablet));
- }
- return Status::OK();
-}
-
-Status FsTool::ListBlocksForTablet(const string& tablet_id) {
- DCHECK(initialized_);
-
- scoped_refptr<TabletMetadata> meta;
- RETURN_NOT_OK(TabletMetadata::Load(fs_manager_.get(), tablet_id, &meta));
-
- if (meta->rowsets().empty()) {
- std::cout << "No rowsets found on disk for tablet " << tablet_id << std::endl;
- return Status::OK();
- }
-
- std::cout << "Listing all data blocks in tablet " << tablet_id << ":" << std::endl;
-
- Schema schema = meta->schema();
-
- size_t idx = 0;
- for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
- std::cout << "Rowset " << idx++ << std::endl;
- RETURN_NOT_OK(ListBlocksInRowSet(schema, *rs_meta));
- }
-
- return Status::OK();
-}
-
-Status FsTool::ListBlocksInRowSet(const Schema& schema,
- const RowSetMetadata& rs_meta) {
- RowSetMetadata::ColumnIdToBlockIdMap col_blocks = rs_meta.GetColumnBlocksById();
- for (const RowSetMetadata::ColumnIdToBlockIdMap::value_type& e : col_blocks) {
- ColumnId col_id = e.first;
- const BlockId& block_id = e.second;
- std::cout << "Column block for column ID " << col_id;
- int col_idx = schema.find_column_by_id(col_id);
- if (col_idx != -1) {
- std::cout << " (" << schema.column(col_idx).ToString() << ")";
- }
- std::cout << ": ";
- std::cout << block_id.ToString() << std::endl;
- }
-
- for (const BlockId& block : rs_meta.undo_delta_blocks()) {
- std::cout << "UNDO: " << block.ToString() << std::endl;
- }
-
- for (const BlockId& block : rs_meta.redo_delta_blocks()) {
- std::cout << "REDO: " << block.ToString() << std::endl;
- }
-
- return Status::OK();
-}
-
-Status FsTool::DumpTabletBlocks(const std::string& tablet_id,
- const DumpOptions& opts,
- int indent) {
- DCHECK(initialized_);
-
- scoped_refptr<TabletMetadata> meta;
- RETURN_NOT_OK(TabletMetadata::Load(fs_manager_.get(), tablet_id, &meta));
-
- if (meta->rowsets().empty()) {
- std::cout << Indent(indent) << "No rowsets found on disk for tablet "
- << tablet_id << std::endl;
- return Status::OK();
- }
-
- Schema schema = meta->schema();
-
- size_t idx = 0;
- for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
- std::cout << std::endl << Indent(indent) << "Dumping rowset " << idx++
- << std::endl << Indent(indent) << kSeparatorLine;
- RETURN_NOT_OK(DumpRowSetInternal(meta->schema(), rs_meta, opts, indent + 2));
- }
- return Status::OK();
-}
-
-Status FsTool::DumpTabletData(const std::string& tablet_id) {
- DCHECK(initialized_);
-
- scoped_refptr<TabletMetadata> meta;
- RETURN_NOT_OK(TabletMetadata::Load(fs_manager_.get(), tablet_id, &meta));
-
- scoped_refptr<log::LogAnchorRegistry> reg(new log::LogAnchorRegistry());
- Tablet t(meta, scoped_refptr<server::Clock>(nullptr), shared_ptr<MemTracker>(),
- nullptr, reg.get());
- RETURN_NOT_OK_PREPEND(t.Open(), "Couldn't open tablet");
- vector<string> lines;
- RETURN_NOT_OK_PREPEND(t.DebugDump(&lines), "Couldn't dump tablet");
- for (const string& line : lines) {
- std::cout << line << std::endl;
- }
- return Status::OK();
-}
-
-Status FsTool::DumpRowSet(const string& tablet_id,
- int64_t rowset_id,
- const DumpOptions& opts,
- int indent) {
- DCHECK(initialized_);
-
- scoped_refptr<TabletMetadata> meta;
- RETURN_NOT_OK(TabletMetadata::Load(fs_manager_.get(), tablet_id, &meta));
-
- for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
- if (rs_meta->id() == rowset_id) {
- return DumpRowSetInternal(meta->schema(), rs_meta, opts, indent);
- }
- }
-
- return Status::InvalidArgument(
- Substitute("Could not find rowset $0 in tablet id $1", rowset_id, tablet_id));
-}
-
-Status FsTool::DumpRowSetInternal(const Schema& schema,
- const shared_ptr<RowSetMetadata>& rs_meta,
- const DumpOptions& opts,
- int indent) {
- tablet::RowSetDataPB pb;
- rs_meta->ToProtobuf(&pb);
-
- std::cout << Indent(indent) << "RowSet metadata: " << pb.DebugString() << std::endl
- << std::endl;
-
- RowSetMetadata::ColumnIdToBlockIdMap col_blocks = rs_meta->GetColumnBlocksById();
- for (const RowSetMetadata::ColumnIdToBlockIdMap::value_type& e : col_blocks) {
- ColumnId col_id = e.first;
- const BlockId& block_id = e.second;
-
- std::cout << Indent(indent) << "Dumping column block " << block_id << " for column id "
- << col_id;
- int col_idx = schema.find_column_by_id(col_id);
- if (col_idx != -1) {
- std::cout << "( " << schema.column(col_idx).ToString() << ")";
- }
- std::cout << ":" << std::endl;
- std::cout << Indent(indent) << kSeparatorLine;
- if (opts.metadata_only) continue;
- RETURN_NOT_OK(DumpCFileBlockInternal(block_id, opts, indent));
- std::cout << std::endl;
- }
-
- for (const BlockId& block : rs_meta->undo_delta_blocks()) {
- std::cout << Indent(indent) << "Dumping undo delta block " << block << ":" << std::endl
- << Indent(indent) << kSeparatorLine;
- RETURN_NOT_OK(DumpDeltaCFileBlockInternal(schema,
- rs_meta,
- block,
- tablet::UNDO,
- opts,
- indent,
- opts.metadata_only));
- std::cout << std::endl;
- }
-
- for (const BlockId& block : rs_meta->redo_delta_blocks()) {
- std::cout << Indent(indent) << "Dumping redo delta block " << block << ":" << std::endl
- << Indent(indent) << kSeparatorLine;
- RETURN_NOT_OK(DumpDeltaCFileBlockInternal(schema,
- rs_meta,
- block,
- tablet::REDO,
- opts,
- indent,
- opts.metadata_only));
- std::cout << std::endl;
- }
-
- return Status::OK();
-}
-
-Status FsTool::DumpCFileBlock(const std::string& block_id_str,
- const DumpOptions &opts,
- int indent) {
- uint64_t numeric_id;
- if (!safe_strtou64(block_id_str, &numeric_id) &&
- !safe_strtou64_base(block_id_str, &numeric_id, 16)) {
- return Status::InvalidArgument(Substitute("block '$0' could not be parsed",
- block_id_str));
- }
- BlockId block_id(numeric_id);
- if (!fs_manager_->BlockExists(block_id)) {
- return Status::NotFound(Substitute("block '$0' does not exist", block_id_str));
- }
- return DumpCFileBlockInternal(block_id, opts, indent);
-}
-
-Status FsTool::PrintUUID(int indent) {
- std::cout << Indent(indent) << fs_manager_->uuid() << std::endl;
- return Status::OK();
-}
-
-Status FsTool::DumpCFileBlockInternal(const BlockId& block_id,
- const DumpOptions& opts,
- int indent) {
- gscoped_ptr<ReadableBlock> block;
- RETURN_NOT_OK(fs_manager_->OpenBlock(block_id, &block));
- gscoped_ptr<CFileReader> reader;
- RETURN_NOT_OK(CFileReader::Open(std::move(block), ReaderOptions(), &reader));
-
- std::cout << Indent(indent) << "CFile Header: "
- << reader->header().ShortDebugString() << std::endl;
- if (detail_level_ <= HEADERS_ONLY) {
- return Status::OK();
- }
- std::cout << Indent(indent) << reader->footer().num_values()
- << " values:" << std::endl;
-
- gscoped_ptr<CFileIterator> it;
- RETURN_NOT_OK(reader->NewIterator(&it, CFileReader::DONT_CACHE_BLOCK));
- RETURN_NOT_OK(it->SeekToFirst());
- return DumpIterator(*reader, it.get(), &std::cout, opts.nrows, indent + 2);
-}
-
-Status FsTool::DumpDeltaCFileBlockInternal(const Schema& schema,
- const shared_ptr<RowSetMetadata>& rs_meta,
- const BlockId& block_id,
- DeltaType delta_type,
- const DumpOptions& opts,
- int indent,
- bool metadata_only) {
- // Open the delta reader
- gscoped_ptr<ReadableBlock> readable_block;
- RETURN_NOT_OK(fs_manager_->OpenBlock(block_id, &readable_block));
- shared_ptr<DeltaFileReader> delta_reader;
- RETURN_NOT_OK(DeltaFileReader::Open(std::move(readable_block),
- block_id,
- &delta_reader,
- delta_type));
-
- std::cout << Indent(indent) << "Delta stats: " << delta_reader->delta_stats().ToString()
- << std::endl;
- if (metadata_only) {
- return Status::OK();
- }
-
- // Create the delta iterator.
- // TODO: see if it's worth re-factoring NewDeltaIterator to return a
- // gscoped_ptr that can then be released if we need a raw or shared
- // pointer.
- DeltaIterator* raw_iter;
-
- MvccSnapshot snap_all;
- if (delta_type == tablet::REDO) {
- snap_all = MvccSnapshot::CreateSnapshotIncludingAllTransactions();
- } else if (delta_type == tablet::UNDO) {
- snap_all = MvccSnapshot::CreateSnapshotIncludingNoTransactions();
- }
-
- Status s = delta_reader->NewDeltaIterator(&schema, snap_all, &raw_iter);
-
- if (s.IsNotFound()) {
- std::cout << "Empty delta block." << std::endl;
- return Status::OK();
- }
- RETURN_NOT_OK(s);
-
- // NewDeltaIterator returns Status::OK() iff a new DeltaIterator is created. Thus,
- // it's safe to have a gscoped_ptr take possesion of 'raw_iter' here.
- gscoped_ptr<DeltaIterator> delta_iter(raw_iter);
- RETURN_NOT_OK(delta_iter->Init(NULL));
- RETURN_NOT_OK(delta_iter->SeekToOrdinal(0));
-
- // TODO: it's awkward that whenever we want to iterate over deltas we also
- // need to open the CFileSet for the rowset. Ideally, we should use information stored
- // in the footer/store additional information in the footer as to make it feasible
- // iterate over all deltas using a DeltaFileIterator alone.
- shared_ptr<CFileSet> cfileset(new CFileSet(rs_meta));
- RETURN_NOT_OK(cfileset->Open());
- gscoped_ptr<CFileSet::Iterator> cfileset_iter(cfileset->NewIterator(&schema));
-
- RETURN_NOT_OK(cfileset_iter->Init(NULL));
-
- const size_t kRowsPerBlock = 100;
- size_t nrows = 0;
- size_t ndeltas = 0;
- Arena arena(32 * 1024, 128 * 1024);
- RowBlock block(schema, kRowsPerBlock, &arena);
-
- // See tablet/delta_compaction.cc to understand why this loop is structured the way
- // it is.
- while (cfileset_iter->HasNext()) {
- size_t n;
- if (opts.nrows > 0) {
- // Note: number of deltas may not equal the number of rows, but
- // since this is a CLI tool (and the nrows option exists
- // primarily to limit copious output) it's okay not to be
- // exact here.
- size_t remaining = opts.nrows - nrows;
- if (remaining == 0) break;
- n = std::min(remaining, kRowsPerBlock);
- } else {
- n = kRowsPerBlock;
- }
-
- arena.Reset();
- cfileset_iter->PrepareBatch(&n);
-
- block.Resize(n);
-
- RETURN_NOT_OK(delta_iter->PrepareBatch(n, DeltaIterator::PREPARE_FOR_COLLECT));
- vector<DeltaKeyAndUpdate> out;
- RETURN_NOT_OK(delta_iter->FilterColumnIdsAndCollectDeltas(vector<ColumnId>(),
- &out,
- &arena));
- for (const DeltaKeyAndUpdate& upd : out) {
- if (detail_level_ > HEADERS_ONLY) {
- std::cout << Indent(indent) << upd.key.ToString() << " "
- << RowChangeList(upd.cell).ToString(schema) << std::endl;
- ++ndeltas;
- }
- }
- RETURN_NOT_OK(cfileset_iter->FinishBatch());
-
- nrows += n;
- }
-
- VLOG(1) << "Processed " << ndeltas << " deltas, for total of " << nrows << " possible rows.";
- return Status::OK();
-}
-
-} // namespace tools
-} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tools/fs_tool.h
----------------------------------------------------------------------
diff --git a/src/kudu/tools/fs_tool.h b/src/kudu/tools/fs_tool.h
deleted file mode 100644
index 5c85c17..0000000
--- a/src/kudu/tools/fs_tool.h
+++ /dev/null
@@ -1,158 +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.
-//
-// Shared fields and methods for querying local files and directories
-#ifndef KUDU_TOOLS_FS_TOOL_H
-#define KUDU_TOOLS_FS_TOOL_H
-
-#include <iostream>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "kudu/gutil/gscoped_ptr.h"
-#include "kudu/util/status.h"
-#include "kudu/tablet/delta_key.h"
-
-namespace kudu {
-
-class FsManager;
-class Schema;
-class BlockId;
-class RandomAccessFile;
-
-namespace tablet {
-class TabletMetadata;
-class RowSetMetadata;
-}
-
-namespace tools {
-
-struct DumpOptions {
- std::string start_key;
- std::string end_key;
- size_t nrows;
- bool metadata_only;
-
- DumpOptions()
- : start_key(""),
- end_key(""),
- nrows(0),
- metadata_only(false) {
- }
-};
-
-class FsTool {
- public:
-
- enum DetailLevel {
- MINIMUM = 0, // Minimum amount of information
- HEADERS_ONLY = 1, // Tablet/segment headers only
- MAXIMUM = 2,
- };
-
- explicit FsTool(DetailLevel detail_level);
- ~FsTool();
-
- Status Init();
-
- // Prints out the file system tree.
- Status FsTree();
-
- // Lists all log segments in the root WALs directory.
- Status ListAllLogSegments();
-
- // Lists all log segments for tablet 'tablet_id'.
- Status ListLogSegmentsForTablet(const std::string& tablet_id);
-
- // Lists all tablets in a tablet server's local file system.
- Status ListAllTablets();
-
- // Prints the header for a log segment residing in 'path'.
- Status PrintLogSegmentHeader(const std::string& path, int indent);
-
- // Lists blocks for a tablet organized by rowset.
- Status ListBlocksForTablet(const std::string& tablet_id);
-
- // Lists blocks for all tablets.
- Status ListBlocksForAllTablets();
-
- // Prints the tablet metadata for a tablet 'tablet_id'.
- Status PrintTabletMeta(const std::string& tablet_id, int indent);
-
- // Dumps the blocks that make up a tablet, rowset by rowset. This ends up
- // outputting on a column-by-column basis, as close as possible to the raw
- // storage. See also: DumpRowSet().
- Status DumpTabletBlocks(const std::string& tablet_id,
- const DumpOptions& opts,
- int indent);
-
- // Dump the data stored in a tablet. The output here is much more readable
- // than DumpTabletBlocks, since it reconstructs rows and associates undo/redo deltas
- // with those rows.
- Status DumpTabletData(const std::string& tablet_id);
-
- // Dumps column blocks, all types of delta blocks for a given
- // rowset.
- Status DumpRowSet(const std::string& tablet_id,
- int64_t rowset_id,
- const DumpOptions& opts,
- int indent);
-
- Status DumpCFileBlock(const std::string& block_id,
- const DumpOptions& opts,
- int indent);
-
- // Prints the server's UUID to whom the data belongs and nothing else.
- Status PrintUUID(int indent);
- private:
- Status ListSegmentsInDir(const std::string& segments_dir);
-
- Status ListBlocksInRowSet(const Schema& schema,
- const tablet::RowSetMetadata& rs_meta);
-
- Status DumpRowSetInternal(const Schema& schema,
- const std::shared_ptr<tablet::RowSetMetadata>& rs_meta,
- const DumpOptions& opts,
- int indent);
-
- Status DumpCFileBlockInternal(const BlockId& block_id,
- const DumpOptions& opts,
- int indent);
-
- Status DumpDeltaCFileBlockInternal(const Schema& schema,
- const std::shared_ptr<tablet::RowSetMetadata>& rs_meta,
- const BlockId& block_id,
- tablet::DeltaType delta_type,
- const DumpOptions& opts,
- int indent,
- bool metadata_only);
-
- Status OpenBlockAsFile(const BlockId& block_id,
- uint64_t* file_size,
- std::shared_ptr<RandomAccessFile>* block_reader);
-
- bool initialized_;
- const DetailLevel detail_level_;
- gscoped_ptr<FsManager> fs_manager_;
-};
-
-} // namespace tools
-} // namespace kudu
-
-#endif // KUDU_TOOLS_FS_TOOL_H
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/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 cf66066..9720d4a 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License.
+#include <memory>
+#include <sstream>
#include <string>
#include <vector>
@@ -24,6 +26,8 @@
#include "kudu/cfile/cfile-test-base.h"
#include "kudu/cfile/cfile_util.h"
#include "kudu/cfile/cfile_writer.h"
+#include "kudu/common/partial_row.h"
+#include "kudu/common/partition.h"
#include "kudu/common/schema.h"
#include "kudu/common/wire_protocol.h"
#include "kudu/common/wire_protocol-test-util.h"
@@ -39,6 +43,9 @@
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/tablet/local_tablet_writer.h"
+#include "kudu/tablet/tablet-harness.h"
+#include "kudu/tablet/tablet_metadata.h"
#include "kudu/tserver/tserver.pb.h"
#include "kudu/util/async_util.h"
#include "kudu/util/env.h"
@@ -61,9 +68,15 @@ using consensus::ReplicateMsg;
using fs::WritableBlock;
using log::Log;
using log::LogOptions;
+using std::ostringstream;
using std::string;
+using std::unique_ptr;
using std::vector;
using strings::Substitute;
+using tablet::LocalTabletWriter;
+using tablet::TabletHarness;
+using tablet::TabletMetadata;
+using tablet::TabletSuperBlockPB;
using tserver::WriteRequestPB;
class ToolTest : public KuduTest {
@@ -183,21 +196,41 @@ TEST_F(ToolTest, TestModeHelp) {
{
const vector<string> kFsModeRegexes = {
"format.*new Kudu filesystem",
- "print_uuid.*UUID of a Kudu filesystem"
+ "dump.*Dump a Kudu filesystem"
};
NO_FATALS(RunTestHelp("fs", kFsModeRegexes));
NO_FATALS(RunTestHelp("fs not_a_mode", kFsModeRegexes,
Status::InvalidArgument("unknown command 'not_a_mode'")));
}
{
+ const vector<string> kFsDumpModeRegexes = {
+ "cfile.*contents of a CFile",
+ "tree.*tree of a Kudu filesystem",
+ "uuid.*UUID of a Kudu filesystem"
+ };
+ NO_FATALS(RunTestHelp("fs dump", kFsDumpModeRegexes));
+
+ }
+ {
const vector<string> kLocalReplicaModeRegexes = {
- "cmeta.*consensus metadata file",
+ "cmeta.*Operate on a local Kudu replica's consensus",
+ "dump.*Dump a Kudu filesystem",
"copy_from_remote.*Copy a replica",
- "dump_wals.*Dump all WAL"
+ "list.*Show list of Kudu replicas"
};
NO_FATALS(RunTestHelp("local_replica", kLocalReplicaModeRegexes));
}
{
+ const vector<string> kLocalReplicaDumpModeRegexes = {
+ "block_ids.*Dump the IDs of all blocks",
+ "meta.*Dump the metadata",
+ "rowset.*Dump the rowset contents",
+ "wals.*Dump all WAL"
+ };
+ NO_FATALS(RunTestHelp("local_replica dump", kLocalReplicaDumpModeRegexes));
+
+ }
+ {
const vector<string> kCmetaModeRegexes = {
"print_replica_uuids.*Print all replica UUIDs",
"rewrite_raft_config.*Rewrite a replica"
@@ -283,7 +316,7 @@ TEST_F(ToolTest, TestFsFormatWithUuid) {
ASSERT_EQ(fs.uuid(), original_uuid);
}
-TEST_F(ToolTest, TestFsPrintUuid) {
+TEST_F(ToolTest, TestFsDumpUuid) {
const string kTestDir = GetTestPath("test");
string uuid;
{
@@ -294,7 +327,7 @@ TEST_F(ToolTest, TestFsPrintUuid) {
}
string stdout;
NO_FATALS(RunActionStdoutString(Substitute(
- "fs print_uuid --fs_wal_dir=$0", kTestDir), &stdout));
+ "fs dump uuid --fs_wal_dir=$0", kTestDir), &stdout));
SCOPED_TRACE(stdout);
ASSERT_EQ(uuid, stdout);
}
@@ -354,13 +387,13 @@ TEST_F(ToolTest, TestFsDumpCFile) {
{
NO_FATALS(RunActionStdoutNone(Substitute(
- "fs dump_cfile --fs_wal_dir=$0 $1 --noprint_meta --noprint_rows",
+ "fs dump cfile --fs_wal_dir=$0 $1 --noprint_meta --noprint_rows",
kTestDir, block_id.ToString())));
}
vector<string> stdout;
{
NO_FATALS(RunActionStdoutLines(Substitute(
- "fs dump_cfile --fs_wal_dir=$0 $1 --noprint_rows",
+ "fs dump cfile --fs_wal_dir=$0 $1 --noprint_rows",
kTestDir, block_id.ToString()), &stdout));
SCOPED_TRACE(stdout);
ASSERT_GE(stdout.size(), 4);
@@ -369,14 +402,14 @@ TEST_F(ToolTest, TestFsDumpCFile) {
}
{
NO_FATALS(RunActionStdoutLines(Substitute(
- "fs dump_cfile --fs_wal_dir=$0 $1 --noprint_meta",
+ "fs dump cfile --fs_wal_dir=$0 $1 --noprint_meta",
kTestDir, block_id.ToString()), &stdout));
SCOPED_TRACE(stdout);
ASSERT_EQ(kNumEntries, stdout.size());
}
{
NO_FATALS(RunActionStdoutLines(Substitute(
- "fs dump_cfile --fs_wal_dir=$0 $1",
+ "fs dump cfile --fs_wal_dir=$0 $1",
kTestDir, block_id.ToString()), &stdout));
SCOPED_TRACE(stdout);
ASSERT_GT(stdout.size(), kNumEntries);
@@ -427,7 +460,7 @@ TEST_F(ToolTest, TestWalDump) {
string wal_path = fs.GetWalSegmentFileName(kTestTablet, 1);
string stdout;
for (const auto& args : { Substitute("wal dump $0", wal_path),
- Substitute("local_replica dump_wals --fs_wal_dir=$0 $1",
+ Substitute("local_replica dump wals --fs_wal_dir=$0 $1",
kTestDir, kTestTablet)
}) {
SCOPED_TRACE(args);
@@ -501,5 +534,192 @@ TEST_F(ToolTest, TestWalDump) {
}
}
+TEST_F(ToolTest, TestLocalReplicaDumpMeta) {
+ const string kTestDir = GetTestPath("test");
+ const string kTestTablet = "test-tablet";
+ const string kTestTableId = "test-table";
+ const string kTestTableName = "test-fs-meta-dump-table";
+ const Schema kSchema(GetSimpleTestSchema());
+ const Schema kSchemaWithIds(SchemaBuilder(kSchema).Build());
+
+ FsManager fs(env_.get(), kTestDir);
+ ASSERT_OK(fs.CreateInitialFileSystemLayout());
+ ASSERT_OK(fs.Open());
+
+ pair<PartitionSchema, Partition> partition = tablet::CreateDefaultPartition(
+ kSchemaWithIds);
+ scoped_refptr<TabletMetadata> meta;
+ TabletMetadata::CreateNew(&fs, kTestTablet, kTestTableName, kTestTableId,
+ kSchemaWithIds, partition.first, partition.second,
+ tablet::TABLET_DATA_READY, &meta);
+ string stdout;
+ NO_FATALS(RunActionStdoutString(Substitute("local_replica dump meta $0 "
+ "--fs_wal_dir=$1 "
+ "--fs_data_dirs=$2",
+ kTestTablet, kTestDir,
+ kTestDir), &stdout));
+
+ // Verify the contents of the metadata output
+ SCOPED_TRACE(stdout);
+ string debug_str = meta->partition_schema()
+ .PartitionDebugString(meta->partition(), meta->schema());
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = Substitute("Table name: $0 Table id: $1",
+ meta->table_name(), meta->table_id());
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = Substitute("Schema (version=$0):", meta->schema_version());
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = meta->schema().ToString();
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+
+ TabletSuperBlockPB pb1;
+ meta->ToSuperBlock(&pb1);
+ debug_str = pb1.DebugString();
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, "Superblock:");
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+}
+
+TEST_F(ToolTest, TestFsDumpTree) {
+ const string kTestDir = GetTestPath("test");
+ const Schema kSchema(GetSimpleTestSchema());
+ const Schema kSchemaWithIds(SchemaBuilder(kSchema).Build());
+
+ FsManager fs(env_.get(), kTestDir);
+ ASSERT_OK(fs.CreateInitialFileSystemLayout());
+ ASSERT_OK(fs.Open());
+
+ string stdout;
+ NO_FATALS(RunActionStdoutString(Substitute("fs dump tree --fs_wal_dir=$0 "
+ "--fs_data_dirs=$1",
+ kTestDir, kTestDir), &stdout));
+
+ // It suffices to verify the contents of the top-level tree structure.
+ SCOPED_TRACE(stdout);
+ ostringstream tree_out;
+ fs.DumpFileSystemTree(tree_out);
+ string tree_out_str = tree_out.str();
+ StripWhiteSpace(&tree_out_str);
+ ASSERT_EQ(stdout, tree_out_str);
+}
+
+TEST_F(ToolTest, TestLocalReplicaOps) {
+ const string kTestDir = GetTestPath("test");
+ const string kTestTablet = "test-tablet";
+ const int kRowId = 100;
+ const Schema kSchema(GetSimpleTestSchema());
+ const Schema kSchemaWithIds(SchemaBuilder(kSchema).Build());
+
+ TabletHarness::Options opts(kTestDir);
+ opts.tablet_id = kTestTablet;
+ TabletHarness harness(kSchemaWithIds, opts);
+ ASSERT_OK(harness.Create(true));
+ ASSERT_OK(harness.Open());
+ LocalTabletWriter writer(harness.tablet().get(), &kSchema);
+ KuduPartialRow row(&kSchemaWithIds);
+ for (int i = 0; i< 10; i++) {
+ ASSERT_OK(row.SetInt32(0, i));
+ ASSERT_OK(row.SetInt32(1, i*10));
+ ASSERT_OK(row.SetStringCopy(2, "HelloWorld"));
+ writer.Insert(row);
+ }
+ harness.tablet()->Flush();
+ harness.tablet()->Shutdown();
+ string fs_paths = "--fs_wal_dir=" + kTestDir + " "
+ "--fs_data_dirs=" + kTestDir;
+ {
+ string stdout;
+ NO_FATALS(RunActionStdoutString(
+ Substitute("local_replica dump block_ids $0 $1",
+ kTestTablet, fs_paths), &stdout));
+
+ SCOPED_TRACE(stdout);
+ string tablet_out = "Listing all data blocks in tablet " + kTestTablet;
+ ASSERT_STR_CONTAINS(stdout, tablet_out);
+ ASSERT_STR_CONTAINS(stdout, "Rowset ");
+ ASSERT_STR_MATCHES(stdout, "Column block for column ID .*");
+ ASSERT_STR_CONTAINS(stdout, "key[int32 NOT NULL]");
+ ASSERT_STR_CONTAINS(stdout, "int_val[int32 NOT NULL]");
+ ASSERT_STR_CONTAINS(stdout, "string_val[string NULLABLE]");
+ }
+ {
+ string stdout;
+ NO_FATALS(RunActionStdoutString(
+ Substitute("local_replica dump rowset $0 $1",
+ kTestTablet, fs_paths), &stdout));
+
+ SCOPED_TRACE(stdout);
+ ASSERT_STR_CONTAINS(stdout, "Dumping rowset 0");
+ ASSERT_STR_MATCHES(stdout, "RowSet metadata: .*");
+ ASSERT_STR_MATCHES(stdout, "last_durable_dms_id: .*");
+ ASSERT_STR_CONTAINS(stdout, "columns {");
+ ASSERT_STR_CONTAINS(stdout, "block {");
+ ASSERT_STR_CONTAINS(stdout, "}");
+ ASSERT_STR_MATCHES(stdout, "column_id:.*");
+ ASSERT_STR_CONTAINS(stdout, "bloom_block {");
+ ASSERT_STR_MATCHES(stdout, "id: .*");
+ ASSERT_STR_CONTAINS(stdout, "undo_deltas {");
+ ASSERT_STR_MATCHES(stdout, "CFile Header: "
+ "major_version: .* minor_version: .*");
+ ASSERT_STR_MATCHES(stdout, "Delta stats:.*");
+ ASSERT_STR_MATCHES(stdout, "ts range=.*");
+ ASSERT_STR_MATCHES(stdout, "update_counts_by_col_id=.*");
+ ASSERT_STR_MATCHES(stdout, "Dumping column block.*for column id.*");
+ ASSERT_STR_MATCHES(stdout, ".*---------------------.*");
+
+ // This is expected to fail with Invalid argument for kRowId.
+ string stderr;
+ Status s = RunTool(
+ Substitute("local_replica dump rowset $0 $1 --rowset_index=$2",
+ kTestTablet, fs_paths, kRowId),
+ &stdout, &stderr, nullptr, nullptr);
+ ASSERT_TRUE(s.IsRuntimeError());
+ SCOPED_TRACE(stderr);
+ string expected = "Could not find rowset " + SimpleItoa(kRowId) +
+ " in tablet id " + kTestTablet;
+ ASSERT_STR_CONTAINS(stderr, expected);
+ }
+ {
+ TabletMetadata* meta = harness.tablet()->metadata();
+ string stdout;
+ string debug_str;
+ NO_FATALS(RunActionStdoutString(
+ Substitute("local_replica dump meta $0 $1",
+ kTestTablet, fs_paths), &stdout));
+
+ SCOPED_TRACE(stdout);
+ debug_str = meta->partition_schema()
+ .PartitionDebugString(meta->partition(), meta->schema());
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = Substitute("Table name: $0 Table id: $1",
+ meta->table_name(), meta->table_id());
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = Substitute("Schema (version=$0):", meta->schema_version());
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ debug_str = meta->schema().ToString();
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+
+ TabletSuperBlockPB pb1;
+ meta->ToSuperBlock(&pb1);
+ debug_str = pb1.DebugString();
+ StripWhiteSpace(&debug_str);
+ ASSERT_STR_CONTAINS(stdout, "Superblock:");
+ ASSERT_STR_CONTAINS(stdout, debug_str);
+ }
+ {
+ string stdout;
+ NO_FATALS(RunActionStdoutString(Substitute("local_replica list $0",
+ fs_paths), &stdout));
+
+ SCOPED_TRACE(stdout);
+ ASSERT_STR_MATCHES(stdout, kTestTablet);
+ }
+}
+
} // namespace tools
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tools/tool_action.h
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action.h b/src/kudu/tools/tool_action.h
index d9e3acf..c03e5d4 100644
--- a/src/kudu/tools/tool_action.h
+++ b/src/kudu/tools/tool_action.h
@@ -50,17 +50,20 @@ class Mode;
// root
// |
// |
-// |
// fs
// | |
// +--+ +--+
// | |
-// format print_uuid
+// format dump
+// | |
+// +--+ +--+
+// | |
+// cfile uuid
//
// Given this tree:
// - "<program> fs" will show all of fs's possible actions.
// - "<program> fs format" will format a filesystem.
-// - "<program> fs print_uuid" will print a filesystem's UUID.
+// - "<program> fs dump uuid" will print a filesystem's UUID.
// Builds a new mode (non-leaf) node.
class ModeBuilder {
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/src/kudu/tools/tool_action_fs.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_fs.cc b/src/kudu/tools/tool_action_fs.cc
index a09a085..f64ecdb 100644
--- a/src/kudu/tools/tool_action_fs.cc
+++ b/src/kudu/tools/tool_action_fs.cc
@@ -29,13 +29,16 @@
#include "kudu/fs/fs_manager.h"
#include "kudu/gutil/strings/numbers.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/tools/tool_action_common.h"
#include "kudu/util/status.h"
DECLARE_bool(print_meta);
DEFINE_bool(print_rows, true,
"Print each row in the CFile");
DEFINE_string(uuid, "",
- "The uuid to use in the filesystem. If not provided, one is generated");
+ "The uuid to use in the filesystem. "
+ "If not provided, one is generated");
+
namespace kudu {
namespace tools {
@@ -59,7 +62,7 @@ Status Format(const RunnerContext& context) {
return fs_manager.CreateInitialFileSystemLayout(uuid);
}
-Status PrintUuid(const RunnerContext& context) {
+Status DumpUuid(const RunnerContext& context) {
FsManagerOpts opts;
opts.read_only = true;
FsManager fs_manager(Env::Default(), opts);
@@ -104,39 +107,64 @@ Status DumpCFile(const RunnerContext& context) {
return Status::OK();
}
+Status DumpFsTree(const RunnerContext& context) {
+ FsManagerOpts fs_opts;
+ fs_opts.read_only = true;
+ FsManager fs_manager(Env::Default(), fs_opts);
+ RETURN_NOT_OK(fs_manager.Open());
+
+ fs_manager.DumpFileSystemTree(std::cout);
+ return Status::OK();
+}
+
} // anonymous namespace
-unique_ptr<Mode> BuildFsMode() {
- unique_ptr<Action> format =
- ActionBuilder("format", &Format)
- .Description("Format a new Kudu filesystem")
+static unique_ptr<Mode> BuildFsDumpMode() {
+ unique_ptr<Action> dump_cfile =
+ ActionBuilder("cfile", &DumpCFile)
+ .Description("Dump the contents of a CFile (column file)")
+ .AddRequiredParameter({ "block_id", "block identifier" })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
- .AddOptionalParameter("uuid")
+ .AddOptionalParameter("print_meta")
+ .AddOptionalParameter("print_rows")
.Build();
- unique_ptr<Action> print_uuid =
- ActionBuilder("print_uuid", &PrintUuid)
- .Description("Print the UUID of a Kudu filesystem")
+ unique_ptr<Action> dump_tree =
+ ActionBuilder("tree", &DumpFsTree)
+ .Description("Dump the tree of a Kudu filesystem")
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.Build();
- unique_ptr<Action> dump_cfile =
- ActionBuilder("dump_cfile", &DumpCFile)
- .Description("Dump the contents of a CFile (column file)")
- .AddRequiredParameter({ "block_id", "block identifier" })
+ unique_ptr<Action> dump_uuid =
+ ActionBuilder("uuid", &DumpUuid)
+ .Description("Dump the UUID of a Kudu filesystem")
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
- .AddOptionalParameter("print_meta")
- .AddOptionalParameter("print_rows")
+ .Build();
+
+ return ModeBuilder("dump")
+ .Description("Dump a Kudu filesystem")
+ .AddAction(std::move(dump_cfile))
+ .AddAction(std::move(dump_tree))
+ .AddAction(std::move(dump_uuid))
+ .Build();
+}
+
+unique_ptr<Mode> BuildFsMode() {
+ unique_ptr<Action> format =
+ ActionBuilder("format", &Format)
+ .Description("Format a new Kudu filesystem")
+ .AddOptionalParameter("fs_wal_dir")
+ .AddOptionalParameter("fs_data_dirs")
+ .AddOptionalParameter("uuid")
.Build();
return ModeBuilder("fs")
.Description("Operate on a local Kudu filesystem")
+ .AddMode(BuildFsDumpMode())
.AddAction(std::move(format))
- .AddAction(std::move(print_uuid))
- .AddAction(std::move(dump_cfile))
.Build();
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/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 d64059b..01986c2 100644
--- a/src/kudu/tools/tool_action_local_replica.cc
+++ b/src/kudu/tools/tool_action_local_replica.cc
@@ -23,34 +23,68 @@
#include <string>
#include <utility>
+#include "kudu/cfile/cfile_reader.h"
+#include "kudu/common/common.pb.h"
+#include "kudu/common/row_changelist.h"
+#include "kudu/common/row_operations.h"
+#include "kudu/common/rowblock.h"
+#include "kudu/common/schema.h"
#include "kudu/common/wire_protocol.h"
#include "kudu/consensus/consensus_meta.h"
+#include "kudu/consensus/consensus.pb.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/human_readable.h"
#include "kudu/gutil/strings/join.h"
+#include "kudu/gutil/strings/numbers.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/stringpiece.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/gutil/strings/util.h"
#include "kudu/master/sys_catalog.h"
#include "kudu/rpc/messenger.h"
+#include "kudu/tablet/cfile_set.h"
+#include "kudu/tablet/deltafile.h"
+#include "kudu/tablet/rowset_metadata.h"
+#include "kudu/tablet/tablet.h"
#include "kudu/tools/tool_action_common.h"
#include "kudu/tserver/tablet_copy_client.h"
+#include "kudu/tserver/tserver.pb.h"
#include "kudu/util/env.h"
#include "kudu/util/env_util.h"
+#include "kudu/util/logging.h"
+#include "kudu/util/mem_tracker.h"
+#include "kudu/util/memory/arena.h"
#include "kudu/util/metrics.h"
#include "kudu/util/net/net_util.h"
+#include "kudu/util/pb_util.h"
#include "kudu/util/status.h"
+DEFINE_bool(metadata_only, false,
+ "Only dump the block metadata when printing blocks.");
+DEFINE_int64(nrows, 0, "Number of rows to dump");
+DEFINE_int64(rowset_index, -1,
+ "Index of the rowset in local replica, default value(-1) "
+ "will dump all the rowsets of the local replica");
+DEFINE_bool(verbose, false,
+ "Print additional information (if any)");
+
namespace kudu {
namespace tools {
+using cfile::CFileIterator;
+using cfile::CFileReader;
+using cfile::DumpIterator;
+using cfile::ReaderOptions;
using consensus::ConsensusMetadata;
using consensus::RaftConfigPB;
using consensus::RaftPeerPB;
+using consensus::ReplicateMsg;
+using fs::ReadableBlock;
using log::LogIndex;
using log::LogReader;
using log::ReadableLogSegment;
@@ -66,10 +100,36 @@ using std::unique_ptr;
using std::vector;
using strings::Split;
using strings::Substitute;
+using tablet::CFileSet;
+using tablet::DeltaFileReader;
+using tablet::DeltaIterator;
+using tablet::DeltaKeyAndUpdate;
+using tablet::DeltaType;
+using tablet::MvccSnapshot;
+using tablet::RowSetMetadata;
+using tablet::Tablet;
+using tablet::TabletMetadata;
using tserver::TabletCopyClient;
+using tserver::WriteRequestPB;
namespace {
+static const char* const kSeparatorLine =
+ "----------------------------------------------------------------------\n";
+
+string Indent(int indent) {
+ return string(indent, ' ');
+}
+
+Status FsInit(unique_ptr<FsManager>* fs_manager) {
+ FsManagerOpts fs_opts;
+ fs_opts.read_only = true;
+ unique_ptr<FsManager> fs_ptr(new FsManager(Env::Default(), fs_opts));
+ RETURN_NOT_OK(fs_ptr->Open());
+ fs_manager->swap(fs_ptr);
+ return Status::OK();
+}
+
// 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.
@@ -108,17 +168,14 @@ Status ParsePeerString(const string& peer_str,
}
Status PrintReplicaUuids(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
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));
+ RETURN_NOT_OK(ConsensusMetadata::Load(fs_manager.get(), tablet_id,
+ fs_manager->uuid(), &cmeta));
cout << JoinMapped(cmeta->committed_config().peers(),
[](const RaftPeerPB& p){ return p.permanent_uuid(); },
" ") << endl;
@@ -153,7 +210,8 @@ Status RewriteRaftConfig(const RunnerContext& context) {
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));
+ 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.
@@ -197,15 +255,12 @@ Status CopyFromRemote(const RunnerContext& context) {
}
Status DumpWals(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
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,
+ RETURN_NOT_OK(LogReader::Open(fs_manager.get(),
scoped_refptr<LogIndex>(),
tablet_id,
scoped_refptr<MetricEntity>(),
@@ -221,12 +276,397 @@ Status DumpWals(const RunnerContext& context) {
return Status::OK();
}
+Status ListBlocksInRowSet(const Schema& schema,
+ const RowSetMetadata& rs_meta) {
+ RowSetMetadata::ColumnIdToBlockIdMap col_blocks =
+ rs_meta.GetColumnBlocksById();
+ for (const RowSetMetadata::ColumnIdToBlockIdMap::value_type& e :
+ col_blocks) {
+ ColumnId col_id = e.first;
+ const BlockId& block_id = e.second;
+ cout << "Column block for column ID " << col_id;
+ int col_idx = schema.find_column_by_id(col_id);
+ if (col_idx != -1) {
+ cout << " (" << schema.column(col_idx).ToString() << ")";
+ }
+ cout << ": ";
+ cout << block_id.ToString() << endl;
+ }
+
+ for (const BlockId& block : rs_meta.undo_delta_blocks()) {
+ cout << "UNDO: " << block.ToString() << endl;
+ }
+
+ for (const BlockId& block : rs_meta.redo_delta_blocks()) {
+ cout << "REDO: " << block.ToString() << endl;
+ }
+
+ return Status::OK();
+}
+
+Status DumpBlockIdsForLocalReplica(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
+ string tablet_id = FindOrDie(context.required_args, "tablet_id");
+
+ scoped_refptr<TabletMetadata> meta;
+ RETURN_NOT_OK(TabletMetadata::Load(fs_manager.get(), tablet_id, &meta));
+
+ if (meta->rowsets().empty()) {
+ cout << "No rowsets found on disk for tablet "
+ << tablet_id << endl;
+ return Status::OK();
+ }
+
+ cout << "Listing all data blocks in tablet "
+ << tablet_id << ":" << endl;
+
+ Schema schema = meta->schema();
+
+ size_t idx = 0;
+ for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
+ cout << "Rowset " << idx++ << endl;
+ RETURN_NOT_OK(ListBlocksInRowSet(schema, *rs_meta));
+ }
+
+ return Status::OK();
+}
+
+Status DumpTabletMeta(FsManager* fs_manager,
+ const string& tablet_id, int indent) {
+ scoped_refptr<TabletMetadata> meta;
+ RETURN_NOT_OK(TabletMetadata::Load(fs_manager, tablet_id, &meta));
+
+ const Schema& schema = meta->schema();
+
+ cout << Indent(indent) << "Partition: "
+ << meta->partition_schema().PartitionDebugString(meta->partition(),
+ meta->schema())
+ << endl;
+ cout << Indent(indent) << "Table name: " << meta->table_name()
+ << " Table id: " << meta->table_id() << endl;
+ cout << Indent(indent) << "Schema (version="
+ << meta->schema_version() << "): "
+ << schema.ToString() << endl;
+
+ tablet::TabletSuperBlockPB pb;
+ RETURN_NOT_OK_PREPEND(meta->ToSuperBlock(&pb), "Could not get superblock");
+ cout << "Superblock:\n" << pb.DebugString() << endl;
+
+ return Status::OK();
+}
+
+Status ListLocalReplicas(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
+
+ vector<string> tablets;
+ RETURN_NOT_OK(fs_manager->ListTabletIds(&tablets));
+ for (const string& tablet : tablets) {
+ if (FLAGS_verbose) {
+ cout << "Tablet: " << tablet << endl;
+ RETURN_NOT_OK(DumpTabletMeta(fs_manager.get(), tablet, 2));
+ } else {
+ cout << tablet << endl;
+ }
+ }
+ return Status::OK();
+}
+
+Status DumpCFileBlockInternal(FsManager* fs_manager,
+ const BlockId& block_id,
+ int indent) {
+ gscoped_ptr<ReadableBlock> block;
+ RETURN_NOT_OK(fs_manager->OpenBlock(block_id, &block));
+ gscoped_ptr<CFileReader> reader;
+ RETURN_NOT_OK(CFileReader::Open(std::move(block), ReaderOptions(), &reader));
+
+ cout << Indent(indent) << "CFile Header: "
+ << reader->header().ShortDebugString() << endl;
+ if (!FLAGS_verbose) {
+ return Status::OK();
+ }
+ cout << Indent(indent) << reader->footer().num_values()
+ << " values:" << endl;
+
+ gscoped_ptr<CFileIterator> it;
+ RETURN_NOT_OK(reader->NewIterator(&it, CFileReader::DONT_CACHE_BLOCK));
+ RETURN_NOT_OK(it->SeekToFirst());
+ return DumpIterator(*reader, it.get(), &cout, FLAGS_nrows, indent + 2);
+}
+
+Status DumpDeltaCFileBlockInternal(FsManager* fs_manager,
+ const Schema& schema,
+ const shared_ptr<RowSetMetadata>& rs_meta,
+ const BlockId& block_id,
+ DeltaType delta_type,
+ int indent) {
+ // Open the delta reader
+ gscoped_ptr<ReadableBlock> readable_block;
+ RETURN_NOT_OK(fs_manager->OpenBlock(block_id, &readable_block));
+ shared_ptr<DeltaFileReader> delta_reader;
+ RETURN_NOT_OK(DeltaFileReader::Open(std::move(readable_block),
+ block_id,
+ &delta_reader,
+ delta_type));
+
+ cout << Indent(indent) << "Delta stats: "
+ << delta_reader->delta_stats().ToString() << endl;
+ if (FLAGS_metadata_only) {
+ return Status::OK();
+ }
+
+ // Create the delta iterator.
+ // TODO: see if it's worth re-factoring NewDeltaIterator to return a
+ // gscoped_ptr that can then be released if we need a raw or shared
+ // pointer.
+ DeltaIterator* raw_iter;
+
+ MvccSnapshot snap_all;
+ if (delta_type == tablet::REDO) {
+ snap_all = MvccSnapshot::CreateSnapshotIncludingAllTransactions();
+ } else if (delta_type == tablet::UNDO) {
+ snap_all = MvccSnapshot::CreateSnapshotIncludingNoTransactions();
+ }
+
+ Status s = delta_reader->NewDeltaIterator(&schema, snap_all, &raw_iter);
+
+ if (s.IsNotFound()) {
+ cout << "Empty delta block." << endl;
+ return Status::OK();
+ }
+ RETURN_NOT_OK(s);
+
+ // NewDeltaIterator returns Status::OK() iff a new DeltaIterator is created. Thus,
+ // it's safe to have a unique_ptr take possesion of 'raw_iter' here.
+ unique_ptr<DeltaIterator> delta_iter(raw_iter);
+ RETURN_NOT_OK(delta_iter->Init(NULL));
+ RETURN_NOT_OK(delta_iter->SeekToOrdinal(0));
+
+ // TODO: it's awkward that whenever we want to iterate over deltas we also
+ // need to open the CFileSet for the rowset. Ideally, we should use
+ // information stored in the footer/store additional information in the
+ // footer as to make it feasible iterate over all deltas using a
+ // DeltaFileIterator alone.
+ shared_ptr<CFileSet> cfileset(new CFileSet(rs_meta));
+ RETURN_NOT_OK(cfileset->Open());
+ gscoped_ptr<CFileSet::Iterator> cfileset_iter(cfileset->NewIterator(&schema));
+
+ RETURN_NOT_OK(cfileset_iter->Init(NULL));
+
+ const size_t kRowsPerBlock = 100;
+ size_t nrows = 0;
+ size_t ndeltas = 0;
+ Arena arena(32 * 1024, 128 * 1024);
+ RowBlock block(schema, kRowsPerBlock, &arena);
+
+ // See tablet/delta_compaction.cc to understand why this loop is structured the way
+ // it is.
+ while (cfileset_iter->HasNext()) {
+ size_t n;
+ if (FLAGS_nrows > 0) {
+ // Note: number of deltas may not equal the number of rows, but
+ // since this is a CLI tool (and the nrows option exists
+ // primarily to limit copious output) it's okay not to be
+ // exact here.
+ size_t remaining = FLAGS_nrows - nrows;
+ if (remaining == 0) break;
+ n = std::min(remaining, kRowsPerBlock);
+ } else {
+ n = kRowsPerBlock;
+ }
+
+ arena.Reset();
+ cfileset_iter->PrepareBatch(&n);
+
+ block.Resize(n);
+
+ RETURN_NOT_OK(delta_iter->PrepareBatch(
+ n, DeltaIterator::PREPARE_FOR_COLLECT));
+ vector<DeltaKeyAndUpdate> out;
+ RETURN_NOT_OK(
+ delta_iter->FilterColumnIdsAndCollectDeltas(vector<ColumnId>(),
+ &out,
+ &arena));
+ for (const DeltaKeyAndUpdate& upd : out) {
+ if (FLAGS_verbose) {
+ cout << Indent(indent) << upd.key.ToString() << " "
+ << RowChangeList(upd.cell).ToString(schema) << endl;
+ ++ndeltas;
+ }
+ }
+ RETURN_NOT_OK(cfileset_iter->FinishBatch());
+
+ nrows += n;
+ }
+
+ VLOG(1) << "Processed " << ndeltas << " deltas, for total of "
+ << nrows << " possible rows.";
+ return Status::OK();
+}
+
+Status DumpRowSetInternal(FsManager* fs_manager,
+ const Schema& schema,
+ const shared_ptr<RowSetMetadata>& rs_meta,
+ int indent) {
+ tablet::RowSetDataPB pb;
+ rs_meta->ToProtobuf(&pb);
+
+ cout << Indent(indent) << "RowSet metadata: " << pb.DebugString()
+ << endl << endl;
+
+ RowSetMetadata::ColumnIdToBlockIdMap col_blocks =
+ rs_meta->GetColumnBlocksById();
+ for (const RowSetMetadata::ColumnIdToBlockIdMap::value_type& e :
+ col_blocks) {
+ ColumnId col_id = e.first;
+ const BlockId& block_id = e.second;
+
+ cout << Indent(indent) << "Dumping column block " << block_id
+ << " for column id " << col_id;
+ int col_idx = schema.find_column_by_id(col_id);
+ if (col_idx != -1) {
+ cout << "( " << schema.column(col_idx).ToString() << ")";
+ }
+ cout << ":" << endl;
+ cout << Indent(indent) << kSeparatorLine;
+ if (FLAGS_metadata_only) continue;
+ RETURN_NOT_OK(DumpCFileBlockInternal(fs_manager, block_id, indent));
+ cout << endl;
+ }
+
+ for (const BlockId& block : rs_meta->undo_delta_blocks()) {
+ cout << Indent(indent) << "Dumping undo delta block " << block << ":"
+ << endl << Indent(indent) << kSeparatorLine;
+ RETURN_NOT_OK(DumpDeltaCFileBlockInternal(fs_manager,
+ schema,
+ rs_meta,
+ block,
+ tablet::UNDO,
+ indent));
+ cout << endl;
+ }
+
+ for (const BlockId& block : rs_meta->redo_delta_blocks()) {
+ cout << Indent(indent) << "Dumping redo delta block " << block << ":"
+ << endl << Indent(indent) << kSeparatorLine;
+ RETURN_NOT_OK(DumpDeltaCFileBlockInternal(fs_manager,
+ schema,
+ rs_meta,
+ block,
+ tablet::REDO,
+ indent));
+ cout << endl;
+ }
+
+ return Status::OK();
+}
+
+Status DumpRowSet(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
+ string tablet_id = FindOrDie(context.required_args, "tablet_id");
+
+ scoped_refptr<TabletMetadata> meta;
+ RETURN_NOT_OK(TabletMetadata::Load(fs_manager.get(), tablet_id, &meta));
+ if (meta->rowsets().empty()) {
+ cout << Indent(0) << "No rowsets found on disk for tablet "
+ << tablet_id << endl;
+ return Status::OK();
+ }
+
+ // If rowset index is provided, only dump that rowset.
+ if (FLAGS_rowset_index != -1) {
+ bool found = false;
+ for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
+ if (rs_meta->id() == FLAGS_rowset_index) {
+ found = true;
+ return DumpRowSetInternal(fs_manager.get(), meta->schema(),
+ rs_meta, 0);
+ }
+ }
+ if (!found) {
+ return Status::InvalidArgument(
+ Substitute("Could not find rowset $0 in tablet id $1",
+ FLAGS_rowset_index, tablet_id));
+ }
+ } else {
+ // Rowset index not provided, dump all rowsets
+ size_t idx = 0;
+ for (const shared_ptr<RowSetMetadata>& rs_meta : meta->rowsets()) {
+ cout << endl << "Dumping rowset " << idx++ << endl << kSeparatorLine;
+ RETURN_NOT_OK(DumpRowSetInternal(fs_manager.get(), meta->schema(),
+ rs_meta, 2));
+ }
+ }
+ return Status::OK();
+}
+
+Status DumpMeta(const RunnerContext& context) {
+ unique_ptr<FsManager> fs_manager;
+ RETURN_NOT_OK(FsInit(&fs_manager));
+ string tablet_id = FindOrDie(context.required_args, "tablet_id");
+ RETURN_NOT_OK(DumpTabletMeta(fs_manager.get(), tablet_id, 0));
+ return Status::OK();
+}
+
+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" })
+ .AddOptionalParameter("fs_wal_dir")
+ .AddOptionalParameter("fs_data_dirs")
+ .Build();
+
+ unique_ptr<Action> dump_meta =
+ ActionBuilder("meta", &DumpMeta)
+ .Description("Dump the metadata of a local replica")
+ .AddRequiredParameter({ "tablet_id", "tablet identifier" })
+ .AddOptionalParameter("fs_wal_dir")
+ .AddOptionalParameter("fs_data_dirs")
+ .Build();
+
+ unique_ptr<Action> dump_rowset =
+ ActionBuilder("rowset", &DumpRowSet)
+ .Description("Dump the rowset contents of a local replica")
+ .AddRequiredParameter({ "tablet_id", "tablet identifier" })
+ .AddOptionalParameter("fs_wal_dir")
+ .AddOptionalParameter("fs_data_dirs")
+ .AddOptionalParameter("metadata_only")
+ .AddOptionalParameter("nrows")
+ .AddOptionalParameter("rowset_index")
+ .AddOptionalParameter("verbose")
+ .Build();
+
+ unique_ptr<Action> dump_wals =
+ ActionBuilder("wals", &DumpWals)
+ .Description("Dump all WAL (write-ahead log) segments of "
+ "a local replica")
+ .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("dump")
+ .Description("Dump a Kudu filesystem")
+ .AddAction(std::move(dump_block_ids))
+ .AddAction(std::move(dump_meta))
+ .AddAction(std::move(dump_rowset))
+ .AddAction(std::move(dump_wals))
+ .Build();
+}
+
} // 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")
+ .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")
@@ -237,14 +677,16 @@ unique_ptr<Mode> BuildLocalReplicaMode() {
.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'" })
+ "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")
+ .Description("Operate on a local Kudu replica's consensus "
+ "metadata file")
.AddAction(std::move(print_replica_uuids))
.AddAction(std::move(rewrite_raft_config))
.Build();
@@ -253,27 +695,26 @@ unique_ptr<Mode> BuildLocalReplicaMode() {
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" })
+ .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" })
+ unique_ptr<Action> list =
+ ActionBuilder("list", &ListLocalReplicas)
+ .Description("Show list of Kudu replicas in the local filesystem")
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
- .AddOptionalParameter("print_entries")
- .AddOptionalParameter("print_meta")
- .AddOptionalParameter("truncate_data")
+ .AddOptionalParameter("verbose")
.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))
+ .AddAction(std::move(list))
+ .AddMode(BuildDumpMode())
.Build();
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/9cb1bcac/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 66ce494..8ed0039 100644
--- a/src/kudu/tools/tool_action_tablet.cc
+++ b/src/kudu/tools/tool_action_tablet.cc
@@ -176,7 +176,6 @@ Status RemoveReplica(const RunnerContext& context) {
return ChangeConfig(context, consensus::REMOVE_SERVER);
}
-
} // anonymous namespace
unique_ptr<Mode> BuildTabletMode() {
[3/3] kudu git commit: tool: port ts-cli
Posted by to...@apache.org.
tool: port ts-cli
I chose to expose common server functionality in new 'master' and 'tserver'
modes rather than consolidating them into a shared 'server' mode; I found
this to be more more intuitive.
I also snuck in a change to ksck to use FLAGS_timeout_ms for RPC timeouts
in client-based operations.
Change-Id: Ifb5a59fd690c2dd09e4e76858469d81f9d501371
Reviewed-on: http://gerrit.cloudera.org:8080/4373
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/14cd22a1
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/14cd22a1
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/14cd22a1
Branch: refs/heads/master
Commit: 14cd22a10b33545c5136ad68ebcf5cc0543ac525
Parents: 9cb1bca
Author: Adar Dembo <ad...@cloudera.com>
Authored: Sun Sep 11 15:13:23 2016 -0700
Committer: Todd Lipcon <to...@apache.org>
Committed: Tue Sep 13 02:14:29 2016 +0000
----------------------------------------------------------------------
build-support/dist_test.py | 1 -
docs/release_notes.adoc | 3 +
src/kudu/client/scan_batch.h | 4 +-
src/kudu/client/schema.h | 6 +-
src/kudu/tablet/tablet_peer.h | 4 +-
src/kudu/tools/CMakeLists.txt | 10 +-
src/kudu/tools/ksck_remote.cc | 1 +
src/kudu/tools/kudu-tool-test.cc | 28 ++
src/kudu/tools/kudu-ts-cli-test.cc | 14 +-
src/kudu/tools/tool_action.h | 3 +
src/kudu/tools/tool_action_common.cc | 132 ++++++
src/kudu/tools/tool_action_common.h | 40 ++
src/kudu/tools/tool_action_master.cc | 97 +++++
src/kudu/tools/tool_action_remote_replica.cc | 331 +++++++++++++++
src/kudu/tools/tool_action_tablet.cc | 11 +-
src/kudu/tools/tool_action_tserver.cc | 98 +++++
src/kudu/tools/tool_main.cc | 3 +
src/kudu/tools/ts-cli.cc | 494 ----------------------
18 files changed, 758 insertions(+), 522 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/build-support/dist_test.py
----------------------------------------------------------------------
diff --git a/build-support/dist_test.py b/build-support/dist_test.py
index d19a78f..003a5dd 100755
--- a/build-support/dist_test.py
+++ b/build-support/dist_test.py
@@ -69,7 +69,6 @@ DEPS_FOR_ALL = \
# TODO: declare these dependencies per-test.
"build/latest/bin/kudu-tserver",
"build/latest/bin/kudu-master",
- "build/latest/bin/kudu-ts-cli",
# parser-test requires these data files.
# TODO: again, we should do this with some per-test metadata file.
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/docs/release_notes.adoc
----------------------------------------------------------------------
diff --git a/docs/release_notes.adoc b/docs/release_notes.adoc
index 9fd83ef..0261d99 100644
--- a/docs/release_notes.adoc
+++ b/docs/release_notes.adoc
@@ -130,6 +130,9 @@ Kudu 1.0.0 are not supported.
- The `kudu-fs_dump` tool has been removed. The same functionality is now
implemented as `kudu fs dump`.
+- The `kudu-ts-cli` tool has been removed. The same functionality is now
+ implemented within `kudu master`, `kudu remote_replica`, and `kudu tserver`.
+
- The `kudu-fs_list` tool has been removed and some similar useful
functionality has been moved under 'kudu local_replica'.
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/client/scan_batch.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/scan_batch.h b/src/kudu/client/scan_batch.h
index 9b1433d..b4d91f6 100644
--- a/src/kudu/client/scan_batch.h
+++ b/src/kudu/client/scan_batch.h
@@ -33,7 +33,7 @@ namespace kudu {
class Schema;
namespace tools {
-class TsAdminClient;
+class ReplicaDumper;
} // namespace tools
namespace client {
@@ -119,7 +119,7 @@ class KUDU_EXPORT KuduScanBatch {
private:
class KUDU_NO_EXPORT Data;
friend class KuduScanner;
- friend class kudu::tools::TsAdminClient;
+ friend class tools::ReplicaDumper;
Data* data_;
DISALLOW_COPY_AND_ASSIGN(KuduScanBatch);
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/client/schema.h
----------------------------------------------------------------------
diff --git a/src/kudu/client/schema.h b/src/kudu/client/schema.h
index 70ba676..a09a88d 100644
--- a/src/kudu/client/schema.h
+++ b/src/kudu/client/schema.h
@@ -33,7 +33,7 @@ class TestWorkload;
namespace tools {
class RemoteKsckMaster;
-class TsAdminClient;
+class ReplicaDumper;
}
namespace client {
@@ -490,8 +490,8 @@ class KUDU_EXPORT KuduSchema {
friend class internal::LookupRpc;
friend class internal::MetaCacheEntry;
friend class internal::WriteRpc;
- friend class kudu::tools::RemoteKsckMaster;
- friend class kudu::tools::TsAdminClient;
+ friend class tools::RemoteKsckMaster;
+ friend class tools::ReplicaDumper;
friend KuduSchema KuduSchemaFromSchema(const Schema& schema);
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tablet/tablet_peer.h
----------------------------------------------------------------------
diff --git a/src/kudu/tablet/tablet_peer.h b/src/kudu/tablet/tablet_peer.h
index 8d72e72..c43c83a 100644
--- a/src/kudu/tablet/tablet_peer.h
+++ b/src/kudu/tablet/tablet_peer.h
@@ -196,9 +196,7 @@ class TabletPeer : public RefCountedThreadSafe<TabletPeer>,
// etc. For use in places like the Web UI.
std::string HumanReadableState() const;
- // Adds list of transactions in-flight at the time of the call to
- // 'out'. TransactionStatusPB objects are used to allow this method
- // to be used by both the web-UI and ts-cli.
+ // Adds list of transactions in-flight at the time of the call to 'out'.
void GetInFlightTransactions(Transaction::TraceType trace_type,
std::vector<consensus::TransactionStatusPB>* out) const;
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/tools/CMakeLists.txt b/src/kudu/tools/CMakeLists.txt
index 0ce2899..54159dc 100644
--- a/src/kudu/tools/CMakeLists.txt
+++ b/src/kudu/tools/CMakeLists.txt
@@ -44,10 +44,6 @@ target_link_libraries(insert-generated-rows
kudu_tools_util
${LINK_LIBS})
-add_executable(kudu-ts-cli ts-cli.cc)
-target_link_libraries(kudu-ts-cli
- ${LINK_LIBS})
-
add_library(ksck
ksck.cc
ksck_remote.cc
@@ -68,9 +64,12 @@ add_executable(kudu
tool_action_common.cc
tool_action_fs.cc
tool_action_local_replica.cc
+ tool_action_master.cc
tool_action_pbc.cc
+ tool_action_remote_replica.cc
tool_action_table.cc
tool_action_tablet.cc
+ tool_action_tserver.cc
tool_action_wal.cc
tool_main.cc
)
@@ -79,6 +78,7 @@ target_link_libraries(kudu
gutil
krpc
ksck
+ kudu_client
kudu_common
kudu_fs
kudu_util
@@ -105,5 +105,5 @@ ADD_KUDU_TEST_DEPENDENCIES(kudu-tool-test
kudu)
ADD_KUDU_TEST(kudu-ts-cli-test)
ADD_KUDU_TEST_DEPENDENCIES(kudu-ts-cli-test
- kudu-ts-cli)
+ kudu)
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/ksck_remote.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/ksck_remote.cc b/src/kudu/tools/ksck_remote.cc
index c2cc85c..1dddfec 100644
--- a/src/kudu/tools/ksck_remote.cc
+++ b/src/kudu/tools/ksck_remote.cc
@@ -262,6 +262,7 @@ void RemoteKsckTabletServer::RunTabletChecksumScanAsync(
Status RemoteKsckMaster::Connect() {
client::sp::shared_ptr<KuduClient> client;
KuduClientBuilder builder;
+ builder.default_rpc_timeout(GetDefaultTimeout());
builder.master_server_addrs(master_addresses_);
return builder.Build(&client_);
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/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 9720d4a..1db59df 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -181,9 +181,12 @@ TEST_F(ToolTest, TestTopLevelHelp) {
"cluster.*Kudu cluster",
"fs.*Kudu filesystem",
"local_replica.*Kudu replicas",
+ "master.*Kudu Master",
"pbc.*protobuf container",
+ "remote_replica.*replicas on a Kudu Tablet Server",
"table.*Kudu tables",
"tablet.*Kudu tablets",
+ "tserver.*Kudu Tablet Server",
"wal.*write-ahead log"
};
NO_FATALS(RunTestHelp("", kTopLevelRegexes));
@@ -244,12 +247,29 @@ TEST_F(ToolTest, TestModeHelp) {
NO_FATALS(RunTestHelp("cluster", kClusterModeRegexes));
}
{
+ const vector<string> kMasterModeRegexes = {
+ "set_flag.*Change a gflag value",
+ "status.*Get the status",
+ "timestamp.*Get the current timestamp"
+ };
+ NO_FATALS(RunTestHelp("master", kMasterModeRegexes));
+ }
+ {
const vector<string> kPbcModeRegexes = {
"dump.*Dump a PBC",
};
NO_FATALS(RunTestHelp("pbc", kPbcModeRegexes));
}
{
+ const vector<string> kRemoteReplicaModeRegexes = {
+ "check.*Check if all replicas",
+ "delete.*Delete a replica",
+ "dump.*Dump the data of a replica",
+ "list.*List all replicas"
+ };
+ NO_FATALS(RunTestHelp("remote_replica", kRemoteReplicaModeRegexes));
+ }
+ {
const vector<string> kTableModeRegexes = {
"delete.*Delete a table",
"list.*List all tables",
@@ -271,6 +291,14 @@ TEST_F(ToolTest, TestModeHelp) {
NO_FATALS(RunTestHelp("tablet change_config", kChangeConfigModeRegexes));
}
{
+ const vector<string> kTServerModeRegexes = {
+ "set_flag.*Change a gflag value",
+ "status.*Get the status",
+ "timestamp.*Get the current timestamp"
+ };
+ NO_FATALS(RunTestHelp("tserver", kTServerModeRegexes));
+ }
+ {
const vector<string> kWalModeRegexes = {
"dump.*Dump a WAL",
};
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/kudu-ts-cli-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-ts-cli-test.cc b/src/kudu/tools/kudu-ts-cli-test.cc
index 6300781..cbcf190 100644
--- a/src/kudu/tools/kudu-ts-cli-test.cc
+++ b/src/kudu/tools/kudu-ts-cli-test.cc
@@ -36,7 +36,7 @@ using strings::Substitute;
namespace kudu {
namespace tools {
-static const char* const kTsCliToolName = "kudu-ts-cli";
+static const char* const kTsCliToolName = "kudu";
class KuduTsCliTest : public ExternalMiniClusterITestBase {
protected:
@@ -78,9 +78,9 @@ TEST_F(KuduTsCliTest, TestDeleteTablet) {
string out;
ASSERT_OK(Subprocess::Call({
GetTsCliToolPath(),
- "--server_address",
+ "remote_replica",
+ "delete",
cluster_->tablet_server(0)->bound_rpc_addr().ToString(),
- "delete_tablet",
tablet_id,
"Deleting for kudu-ts-cli-test"
}, &out));
@@ -117,9 +117,9 @@ TEST_F(KuduTsCliTest, TestDumpTablet) {
// Test for dump_tablet when there is no data in tablet.
ASSERT_OK(Subprocess::Call({
GetTsCliToolPath(),
- "--server_address",
+ "remote_replica",
+ "dump",
cluster_->tablet_server(0)->bound_rpc_addr().ToString(),
- "dump_tablet",
tablet_id
}, &out));
ASSERT_EQ("", out);
@@ -133,9 +133,9 @@ TEST_F(KuduTsCliTest, TestDumpTablet) {
ASSERT_OK(WaitForServersToAgree(timeout, ts_map_, tablet_id, workload.batches_completed()));
ASSERT_OK(Subprocess::Call({
GetTsCliToolPath(),
- "--server_address",
+ "remote_replica",
+ "dump",
cluster_->tablet_server(0)->bound_rpc_addr().ToString(),
- "dump_tablet",
tablet_id
}, &out));
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/tool_action.h
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action.h b/src/kudu/tools/tool_action.h
index c03e5d4..95aa162 100644
--- a/src/kudu/tools/tool_action.h
+++ b/src/kudu/tools/tool_action.h
@@ -278,9 +278,12 @@ class Action {
std::unique_ptr<Mode> BuildClusterMode();
std::unique_ptr<Mode> BuildFsMode();
std::unique_ptr<Mode> BuildLocalReplicaMode();
+std::unique_ptr<Mode> BuildMasterMode();
std::unique_ptr<Mode> BuildPbcMode();
+std::unique_ptr<Mode> BuildRemoteReplicaMode();
std::unique_ptr<Mode> BuildTableMode();
std::unique_ptr<Mode> BuildTabletMode();
+std::unique_ptr<Mode> BuildTServerMode();
std::unique_ptr<Mode> BuildWalMode();
} // namespace tools
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/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 1daa12d..bbcf981 100644
--- a/src/kudu/tools/tool_action_common.cc
+++ b/src/kudu/tools/tool_action_common.cc
@@ -18,6 +18,7 @@
#include "kudu/tools/tool_action_common.h"
#include <iostream>
+#include <memory>
#include <string>
#include <vector>
@@ -29,16 +30,32 @@
#include "kudu/common/row_operations.h"
#include "kudu/common/wire_protocol.h"
#include "kudu/consensus/consensus.pb.h"
+#include "kudu/consensus/consensus.proxy.h"
#include "kudu/consensus/log.pb.h"
#include "kudu/consensus/log_util.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/numbers.h"
+#include "kudu/rpc/messenger.h"
+#include "kudu/rpc/rpc_controller.h"
#include "kudu/rpc/rpc_header.pb.h"
+#include "kudu/server/server_base.pb.h"
+#include "kudu/server/server_base.proxy.h"
#include "kudu/tserver/tserver.pb.h"
+#include "kudu/tserver/tserver_admin.proxy.h"
+#include "kudu/tserver/tserver_service.proxy.h"
#include "kudu/util/memory/arena.h"
+#include "kudu/util/monotime.h"
+#include "kudu/util/net/net_util.h"
+#include "kudu/util/net/sockaddr.h"
#include "kudu/util/pb_util.h"
#include "kudu/util/status.h"
+DECLARE_int64(timeout_ms); // defined in ksck
+
+DEFINE_bool(force, false, "If true, allows the set_flag command to set a flag "
+ "which is not explicitly marked as runtime-settable. Such flag "
+ "changes may be simply ignored on the server, or may cause the "
+ "server to crash.");
DEFINE_bool(print_meta, true, "Include metadata in output");
DEFINE_string(print_entries, "decoded",
"How to print entries:\n"
@@ -53,16 +70,32 @@ DEFINE_int32(truncate_data, 100,
namespace kudu {
namespace tools {
+using consensus::ConsensusServiceProxy;
using consensus::ReplicateMsg;
using log::LogEntryPB;
using log::LogEntryReader;
using log::ReadableLogSegment;
+using rpc::Messenger;
+using rpc::MessengerBuilder;
using rpc::RequestIdPB;
+using rpc::RpcController;
+using server::GenericServiceProxy;
+using server::GetStatusRequestPB;
+using server::GetStatusResponsePB;
+using server::ServerClockRequestPB;
+using server::ServerClockResponsePB;
+using server::ServerStatusPB;
+using server::SetFlagRequestPB;
+using server::SetFlagResponsePB;
using std::cout;
using std::cerr;
using std::endl;
+using std::shared_ptr;
using std::string;
+using std::unique_ptr;
using std::vector;
+using tserver::TabletServerAdminServiceProxy;
+using tserver::TabletServerServiceProxy;
using tserver::WriteRequestPB;
namespace {
@@ -170,6 +203,55 @@ Status PrintDecoded(const LogEntryPB& entry, const Schema& tablet_schema) {
} // anonymous namespace
+template<class ProxyClass>
+Status BuildProxy(const string& address,
+ uint16_t default_port,
+ unique_ptr<ProxyClass>* proxy) {
+ HostPort hp;
+ RETURN_NOT_OK(hp.ParseString(address, default_port));
+ shared_ptr<Messenger> messenger;
+ RETURN_NOT_OK(MessengerBuilder("tool").Build(&messenger));
+
+ vector<Sockaddr> resolved;
+ RETURN_NOT_OK(hp.ResolveAddresses(&resolved));
+
+ proxy->reset(new ProxyClass(messenger, resolved[0]));
+ return Status::OK();
+}
+
+// Explicit specialization for callers outside this compilation unit.
+template
+Status BuildProxy(const string& address,
+ uint16_t default_port,
+ unique_ptr<ConsensusServiceProxy>* proxy);
+template
+Status BuildProxy(const string& address,
+ uint16_t default_port,
+ unique_ptr<TabletServerServiceProxy>* proxy);
+template
+Status BuildProxy(const string& address,
+ uint16_t default_port,
+ unique_ptr<TabletServerAdminServiceProxy>* proxy);
+
+Status GetServerStatus(const string& address, uint16_t default_port,
+ ServerStatusPB* status) {
+ unique_ptr<GenericServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, default_port, &proxy));
+
+ GetStatusRequestPB req;
+ GetStatusResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+
+ RETURN_NOT_OK(proxy->GetStatus(req, &resp, &rpc));
+ if (!resp.has_status()) {
+ return Status::Incomplete("Server response did not contain status",
+ proxy->ToString());
+ }
+ *status = resp.status();
+ return Status::OK();
+}
+
Status PrintSegment(const scoped_refptr<ReadableLogSegment>& segment) {
PrintEntryType print_type = ParsePrintType();
if (FLAGS_print_meta) {
@@ -206,5 +288,55 @@ Status PrintSegment(const scoped_refptr<ReadableLogSegment>& segment) {
return Status::OK();
}
+Status SetServerFlag(const string& address, uint16_t default_port,
+ const string& flag, const string& value) {
+ unique_ptr<GenericServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, default_port, &proxy));
+
+ SetFlagRequestPB req;
+ SetFlagResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+
+ req.set_flag(flag);
+ req.set_value(value);
+ req.set_force(FLAGS_force);
+
+ RETURN_NOT_OK(proxy->SetFlag(req, &resp, &rpc));
+ switch (resp.result()) {
+ case server::SetFlagResponsePB::SUCCESS:
+ return Status::OK();
+ case server::SetFlagResponsePB::NOT_SAFE:
+ return Status::RemoteError(resp.msg() +
+ " (use --force flag to allow anyway)");
+ default:
+ return Status::RemoteError(resp.ShortDebugString());
+ }
+}
+
+Status PrintServerStatus(const string& address, uint16_t default_port) {
+ ServerStatusPB status;
+ RETURN_NOT_OK(GetServerStatus(address, default_port, &status));
+ cout << status.DebugString() << endl;
+ return Status::OK();
+}
+
+Status PrintServerTimestamp(const string& address, uint16_t default_port) {
+ unique_ptr<GenericServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, default_port, &proxy));
+
+ ServerClockRequestPB req;
+ ServerClockResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+ RETURN_NOT_OK(proxy->ServerClock(req, &resp, &rpc));
+ if (!resp.has_timestamp()) {
+ return Status::Incomplete("Server response did not contain timestamp",
+ proxy->ToString());
+ }
+ cout << resp.timestamp() << endl;
+ return Status::OK();
+}
+
} // namespace tools
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/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 0391bb3..d51f656 100644
--- a/src/kudu/tools/tool_action_common.h
+++ b/src/kudu/tools/tool_action_common.h
@@ -17,6 +17,9 @@
#pragma once
+#include <memory>
+#include <string>
+
#include "kudu/gutil/ref_counted.h"
#include "kudu/util/status.h"
@@ -26,10 +29,30 @@ namespace log {
class ReadableLogSegment;
} // namespace log
+namespace server {
+class ServerStatusPB;
+} // namespace server
+
namespace tools {
// Utility methods used by multiple actions across different modes.
+// Builds a proxy to a Kudu server running at 'address', returning it in
+// 'proxy'.
+//
+// If 'address' does not contain a port, 'default_port' is used instead.
+template<class ProxyClass>
+Status BuildProxy(const std::string& address,
+ uint16_t default_port,
+ std::unique_ptr<ProxyClass>* proxy);
+
+// Get the current status of the Kudu server running at 'address', storing it
+// in 'status'.
+//
+// If 'address' does not contain a port, 'default_port' is used instead.
+Status GetServerStatus(const std::string& address, uint16_t default_port,
+ server::ServerStatusPB* status);
+
// Prints the contents of a WAL segment to stdout.
//
// The following gflags affect the output:
@@ -38,5 +61,22 @@ namespace tools {
// - truncate_data: how many bytes to print for each data field.
Status PrintSegment(const scoped_refptr<log::ReadableLogSegment>& segment);
+// Print the current status of the Kudu server running at 'address'.
+//
+// If 'address' does not contain a port, 'default_port' is used instead.
+Status PrintServerStatus(const std::string& address, uint16_t default_port);
+
+// Print the current timestamp of the Kudu server running at 'address'.
+//
+// If 'address' does not contain a port, 'default_port' is used instead.
+Status PrintServerTimestamp(const std::string& address, uint16_t default_port);
+
+// Changes the value of the gflag given by 'flag' to the value in 'value' on
+// the Kudu server running at 'address'.
+//
+// If 'address' does not contain a port, 'default_port' is used instead.
+Status SetServerFlag(const std::string& address, uint16_t default_port,
+ const std::string& flag, const std::string& value);
+
} // namespace tools
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/tool_action_master.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_master.cc b/src/kudu/tools/tool_action_master.cc
new file mode 100644
index 0000000..aea53d1
--- /dev/null
+++ b/src/kudu/tools/tool_action_master.cc
@@ -0,0 +1,97 @@
+// 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 <memory>
+#include <string>
+#include <utility>
+
+#include <gflags/gflags.h>
+
+#include "kudu/gutil/map-util.h"
+#include "kudu/master/master.h"
+#include "kudu/tools/tool_action_common.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+namespace tools {
+
+using std::string;
+using std::unique_ptr;
+
+namespace {
+
+const char* const kMasterAddressArg = "master_address";
+const char* const kMasterAddressDesc = "Address of a Kudu Master of form "
+ "'hostname:port'. Port may be omitted if the Master is bound to the "
+ "default port.";
+const char* const kFlagArg = "flag";
+const char* const kValueArg = "value";
+
+Status MasterSetFlag(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kMasterAddressArg);
+ string flag = FindOrDie(context.required_args, kFlagArg);
+ string value = FindOrDie(context.required_args, kValueArg);
+ return SetServerFlag(address, master::Master::kDefaultPort, flag, value);
+}
+
+Status MasterStatus(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kMasterAddressArg);
+ return PrintServerStatus(address, master::Master::kDefaultPort);
+}
+
+Status MasterTimestamp(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kMasterAddressArg);
+ return PrintServerTimestamp(address, master::Master::kDefaultPort);
+}
+
+} // anonymous namespace
+
+unique_ptr<Mode> BuildMasterMode() {
+ unique_ptr<Action> set_flag =
+ ActionBuilder("set_flag", &MasterSetFlag)
+ .Description("Change a gflag value on a Kudu Master")
+ .AddRequiredParameter({ kMasterAddressArg, kMasterAddressDesc })
+ .AddRequiredParameter({ kFlagArg, "Name of the gflag" })
+ .AddRequiredParameter({ kValueArg, "New value for the gflag" })
+ .AddOptionalParameter("force")
+ .Build();
+
+ unique_ptr<Action> status =
+ ActionBuilder("status", &MasterStatus)
+ .Description("Get the status of a Kudu Master")
+ .AddRequiredParameter({ kMasterAddressArg, kMasterAddressDesc })
+ .Build();
+
+ unique_ptr<Action> timestamp =
+ ActionBuilder("timestamp", &MasterTimestamp)
+ .Description("Get the current timestamp of a Kudu Master")
+ .AddRequiredParameter({ kMasterAddressArg, kMasterAddressDesc })
+ .Build();
+
+ return ModeBuilder("master")
+ .Description("Operate on a Kudu Master")
+ .AddAction(std::move(set_flag))
+ .AddAction(std::move(status))
+ .AddAction(std::move(timestamp))
+ .Build();
+}
+
+} // namespace tools
+} // namespace kudu
+
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/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
new file mode 100644
index 0000000..8ee7cb9
--- /dev/null
+++ b/src/kudu/tools/tool_action_remote_replica.cc
@@ -0,0 +1,331 @@
+// 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 <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <gflags/gflags.h>
+
+#include "kudu/client/client.h"
+#include "kudu/client/row_result.h"
+#include "kudu/client/scan_batch.h"
+#include "kudu/client/scanner-internal.h"
+#include "kudu/common/partition.h"
+#include "kudu/common/schema.h"
+#include "kudu/common/wire_protocol.h"
+#include "kudu/gutil/gscoped_ptr.h"
+#include "kudu/gutil/map-util.h"
+#include "kudu/gutil/strings/human_readable.h"
+#include "kudu/server/server_base.pb.h"
+#include "kudu/tablet/tablet.pb.h"
+#include "kudu/tools/tool_action_common.h"
+#include "kudu/tserver/tablet_server.h"
+#include "kudu/tserver/tserver.pb.h"
+#include "kudu/tserver/tserver_admin.proxy.h"
+#include "kudu/tserver/tserver_service.proxy.h"
+#include "kudu/rpc/messenger.h"
+#include "kudu/rpc/rpc_controller.h"
+#include "kudu/util/net/net_util.h"
+#include "kudu/util/net/sockaddr.h"
+#include "kudu/util/status.h"
+
+DECLARE_int64(timeout_ms); // defined in ksck
+
+namespace kudu {
+namespace tools {
+
+using client::KuduRowResult;
+using client::KuduScanBatch;
+using client::KuduSchema;
+using rpc::Messenger;
+using rpc::MessengerBuilder;
+using rpc::RpcController;
+using server::ServerStatusPB;
+using std::cerr;
+using std::cout;
+using std::endl;
+using std::shared_ptr;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+using tablet::TabletStatusPB;
+using tserver::DeleteTabletRequestPB;
+using tserver::DeleteTabletResponsePB;
+using tserver::ListTabletsRequestPB;
+using tserver::ListTabletsResponsePB;
+using tserver::NewScanRequestPB;
+using tserver::ScanRequestPB;
+using tserver::ScanResponsePB;
+using tserver::TabletServerAdminServiceProxy;
+using tserver::TabletServerServiceProxy;
+
+// This class only exists so that Dump() can easily be friended with
+// KuduSchema and KuduScanBatch.
+class ReplicaDumper {
+ public:
+ static Status Dump(const Schema& schema,
+ const string& tablet_id,
+ TabletServerServiceProxy* proxy) {
+ KuduSchema client_schema(schema);
+
+ ScanRequestPB req;
+ ScanResponsePB resp;
+
+ NewScanRequestPB* new_req = req.mutable_new_scan_request();
+ RETURN_NOT_OK(SchemaToColumnPBs(
+ schema, new_req->mutable_projected_columns(),
+ SCHEMA_PB_WITHOUT_IDS | SCHEMA_PB_WITHOUT_STORAGE_ATTRIBUTES));
+ new_req->set_tablet_id(tablet_id);
+ new_req->set_cache_blocks(false);
+ new_req->set_order_mode(ORDERED);
+ new_req->set_read_mode(READ_AT_SNAPSHOT);
+
+ do {
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+ RETURN_NOT_OK_PREPEND(proxy->Scan(req, &resp, &rpc), "Scan() failed");
+
+ if (resp.has_error()) {
+ return Status::IOError("Failed to read: ",
+ resp.error().ShortDebugString());
+ }
+
+ // The first response has a scanner ID. We use this for all subsequent
+ // responses.
+ if (resp.has_scanner_id()) {
+ req.set_scanner_id(resp.scanner_id());
+ req.clear_new_scan_request();
+ }
+ req.set_call_seq_id(req.call_seq_id() + 1);
+
+ // Nothing to process from this scan result.
+ if (!resp.has_data()) {
+ continue;
+ }
+
+ KuduScanBatch::Data results;
+ RETURN_NOT_OK(results.Reset(&rpc,
+ &schema,
+ &client_schema,
+ make_gscoped_ptr(resp.release_data())));
+ vector<KuduRowResult> rows;
+ results.ExtractRows(&rows);
+ for (const auto& r : rows) {
+ cout << r.ToString() << endl;
+ }
+ } while (resp.has_more_results());
+ return Status::OK();
+ }
+};
+
+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 "
+ "to the default port.";
+
+Status GetReplicas(TabletServerServiceProxy* proxy,
+ vector<ListTabletsResponsePB::StatusAndSchemaPB>* replicas) {
+ ListTabletsRequestPB req;
+ ListTabletsResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+
+ RETURN_NOT_OK(proxy->ListTablets(req, &resp, &rpc));
+ if (resp.has_error()) {
+ return StatusFromPB(resp.error().status());
+ }
+
+ replicas->assign(resp.status_and_schema().begin(),
+ resp.status_and_schema().end());
+ return Status::OK();
+}
+
+Status CheckReplicas(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+
+ unique_ptr<TabletServerServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, tserver::TabletServer::kDefaultPort,
+ &proxy));
+
+ vector<ListTabletsResponsePB::StatusAndSchemaPB> replicas;
+ RETURN_NOT_OK(GetReplicas(proxy.get(), &replicas));
+
+ bool all_running = true;
+ for (const auto& r : replicas) {
+ TabletStatusPB rs = r.tablet_status();
+ if (rs.state() != tablet::RUNNING) {
+ cerr << "Tablet id: " << rs.tablet_id() << " is "
+ << tablet::TabletStatePB_Name(rs.state()) << endl;
+ all_running = false;
+ }
+ }
+
+ if (all_running) {
+ cout << "All tablets are running" << endl;
+ return Status::OK();
+ } else {
+ return Status::IllegalState("Not all tablets are running");
+ }
+}
+
+Status DeleteReplica(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ string tablet_id = FindOrDie(context.required_args, kTabletArg);
+ string reason = FindOrDie(context.required_args, kReasonArg);
+
+ ServerStatusPB status;
+ RETURN_NOT_OK(GetServerStatus(address, tserver::TabletServer::kDefaultPort,
+ &status));
+
+ unique_ptr<TabletServerAdminServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, tserver::TabletServer::kDefaultPort,
+ &proxy));
+
+ DeleteTabletRequestPB req;
+ DeleteTabletResponsePB resp;
+ RpcController rpc;
+ rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
+
+ req.set_tablet_id(tablet_id);
+ req.set_dest_uuid(status.node_instance().permanent_uuid());
+ req.set_reason(reason);
+ req.set_delete_type(tablet::TABLET_DATA_TOMBSTONED);
+ RETURN_NOT_OK_PREPEND(proxy->DeleteTablet(req, &resp, &rpc),
+ "DeleteTablet() failed");
+ if (resp.has_error()) {
+ return Status::IOError("Failed to delete tablet: ",
+ resp.error().ShortDebugString());
+ }
+ return Status::OK();
+}
+
+Status DumpReplica(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ string tablet_id = FindOrDie(context.required_args, kTabletArg);
+
+ unique_ptr<TabletServerServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, tserver::TabletServer::kDefaultPort,
+ &proxy));
+
+ vector<ListTabletsResponsePB::StatusAndSchemaPB> replicas;
+ RETURN_NOT_OK(GetReplicas(proxy.get(), &replicas));
+
+ Schema schema;
+ for (const auto& r : replicas) {
+ if (r.tablet_status().tablet_id() == tablet_id) {
+ RETURN_NOT_OK(SchemaFromPB(r.schema(), &schema));
+ break;
+ }
+ }
+ if (!schema.initialized()) {
+ return Status::NotFound("cannot find replica", tablet_id);
+ }
+ return ReplicaDumper::Dump(schema, tablet_id, proxy.get());
+}
+
+Status ListReplicas(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ unique_ptr<TabletServerServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(address, tserver::TabletServer::kDefaultPort,
+ &proxy));
+
+ vector<ListTabletsResponsePB::StatusAndSchemaPB> replicas;
+ RETURN_NOT_OK(GetReplicas(proxy.get(), &replicas));
+
+ for (const auto& r : replicas) {
+ Schema schema;
+ RETURN_NOT_OK_PREPEND(
+ SchemaFromPB(r.schema(), &schema),
+ "Unable to deserialize schema from " + address);
+ PartitionSchema partition_schema;
+ RETURN_NOT_OK_PREPEND(
+ PartitionSchema::FromPB(r.partition_schema(), schema, &partition_schema),
+ "Unable to deserialize partition schema from " + address);
+
+ const TabletStatusPB& rs = r.tablet_status();
+
+ Partition partition;
+ Partition::FromPB(rs.partition(), &partition);
+
+ string state = tablet::TabletStatePB_Name(rs.state());
+ cout << "Tablet id: " << rs.tablet_id() << endl;
+ cout << "State: " << state << endl;
+ cout << "Table name: " << rs.table_name() << endl;
+ cout << "Partition: "
+ << partition_schema.PartitionDebugString(partition, schema) << endl;
+ if (rs.has_estimated_on_disk_size()) {
+ cout << "Estimated on disk size: "
+ << HumanReadableNumBytes::ToString(rs.estimated_on_disk_size()) << endl;
+ }
+ cout << "Schema: " << schema.ToString() << endl;
+ }
+
+ return Status::OK();
+}
+
+} // anonymous namespace
+
+unique_ptr<Mode> BuildRemoteReplicaMode() {
+ unique_ptr<Action> check_replicas =
+ ActionBuilder("check", &CheckReplicas)
+ .Description("Check if all replicas on a Kudu Tablet Server are running")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .Build();
+
+ unique_ptr<Action> delete_replica =
+ ActionBuilder("delete", &DeleteReplica)
+ .Description("Delete a replica from a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .AddRequiredParameter({ kTabletArg, kTabletDesc })
+ .AddRequiredParameter({ kReasonArg, "Reason for deleting the replica" })
+ .Build();
+
+ unique_ptr<Action> dump_replica =
+ ActionBuilder("dump", &DumpReplica)
+ .Description("Dump the data of a replica on a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .AddRequiredParameter({ kTabletArg, kTabletDesc })
+ .Build();
+
+ unique_ptr<Action> list =
+ ActionBuilder("list", &ListReplicas)
+ .Description("List all replicas on a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .Build();
+
+ return ModeBuilder("remote_replica")
+ .Description("Operate on replicas on a Kudu Tablet Server")
+ .AddAction(std::move(check_replicas))
+ .AddAction(std::move(delete_replica))
+ .AddAction(std::move(dump_replica))
+ .AddAction(std::move(list))
+ .Build();
+}
+
+} // namespace tools
+} // namespace kudu
+
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/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 8ed0039..86e3df7 100644
--- a/src/kudu/tools/tool_action_tablet.cc
+++ b/src/kudu/tools/tool_action_tablet.cc
@@ -30,8 +30,8 @@
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
-#include "kudu/rpc/messenger.h"
#include "kudu/rpc/rpc_controller.h"
+#include "kudu/tools/tool_action_common.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/status.h"
#include "kudu/util/string_case.h"
@@ -46,8 +46,6 @@ using client::KuduTabletServer;
using consensus::ChangeConfigType;
using consensus::ConsensusServiceProxy;
using consensus::RaftPeerPB;
-using rpc::Messenger;
-using rpc::MessengerBuilder;
using rpc::RpcController;
using std::shared_ptr;
using std::string;
@@ -145,9 +143,8 @@ Status ChangeConfig(const RunnerContext& context, ChangeConfigType cc_type) {
leader_hp.ToString());
}
- shared_ptr<Messenger> messenger;
- RETURN_NOT_OK(MessengerBuilder("kudu").Build(&messenger));
- ConsensusServiceProxy proxy(messenger, leader_addrs[0]);
+ unique_ptr<ConsensusServiceProxy> proxy;
+ RETURN_NOT_OK(BuildProxy(leader_hp.host(), leader_hp.port(), &proxy));
consensus::ChangeConfigRequestPB req;
consensus::ChangeConfigResponsePB resp;
@@ -157,7 +154,7 @@ Status ChangeConfig(const RunnerContext& context, ChangeConfigType cc_type) {
req.set_tablet_id(tablet_id);
req.set_type(cc_type);
*req.mutable_server() = peer_pb;
- RETURN_NOT_OK(proxy.ChangeConfig(req, &resp, &rpc));
+ RETURN_NOT_OK(proxy->ChangeConfig(req, &resp, &rpc));
if (resp.has_error()) {
return StatusFromPB(resp.error().status());
}
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/tool_action_tserver.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_tserver.cc b/src/kudu/tools/tool_action_tserver.cc
new file mode 100644
index 0000000..145ec1b
--- /dev/null
+++ b/src/kudu/tools/tool_action_tserver.cc
@@ -0,0 +1,98 @@
+// 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 <memory>
+#include <string>
+#include <utility>
+
+#include <gflags/gflags.h>
+
+#include "kudu/gutil/map-util.h"
+#include "kudu/tools/tool_action_common.h"
+#include "kudu/tserver/tablet_server.h"
+#include "kudu/util/status.h"
+
+namespace kudu {
+namespace tools {
+
+using std::string;
+using std::unique_ptr;
+
+namespace {
+
+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 "
+ "to the default port.";
+const char* const kFlagArg = "flag";
+const char* const kValueArg = "value";
+
+Status TServerSetFlag(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ string flag = FindOrDie(context.required_args, kFlagArg);
+ string value = FindOrDie(context.required_args, kValueArg);
+ return SetServerFlag(address, tserver::TabletServer::kDefaultPort,
+ flag, value);
+}
+
+Status TServerStatus(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ return PrintServerStatus(address, tserver::TabletServer::kDefaultPort);
+}
+
+Status TServerTimestamp(const RunnerContext& context) {
+ string address = FindOrDie(context.required_args, kTServerAddressArg);
+ return PrintServerTimestamp(address, tserver::TabletServer::kDefaultPort);
+}
+
+} // anonymous namespace
+
+unique_ptr<Mode> BuildTServerMode() {
+ unique_ptr<Action> set_flag =
+ ActionBuilder("set_flag", &TServerSetFlag)
+ .Description("Change a gflag value on a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .AddRequiredParameter({ kFlagArg, "Name of the gflag" })
+ .AddRequiredParameter({ kValueArg, "New value for the gflag" })
+ .AddOptionalParameter("force")
+ .Build();
+
+ unique_ptr<Action> status =
+ ActionBuilder("status", &TServerStatus)
+ .Description("Get the status of a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .Build();
+
+ unique_ptr<Action> timestamp =
+ ActionBuilder("timestamp", &TServerTimestamp)
+ .Description("Get the current timestamp of a Kudu Tablet Server")
+ .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc })
+ .Build();
+
+ return ModeBuilder("tserver")
+ .Description("Operate on a Kudu Tablet Server")
+ .AddAction(std::move(set_flag))
+ .AddAction(std::move(status))
+ .AddAction(std::move(timestamp))
+ .Build();
+}
+
+} // namespace tools
+} // namespace kudu
+
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/tool_main.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_main.cc b/src/kudu/tools/tool_main.cc
index 3c8bb63..caf3bde 100644
--- a/src/kudu/tools/tool_main.cc
+++ b/src/kudu/tools/tool_main.cc
@@ -114,9 +114,12 @@ int RunTool(int argc, char** argv, bool show_help) {
.AddMode(BuildClusterMode())
.AddMode(BuildFsMode())
.AddMode(BuildLocalReplicaMode())
+ .AddMode(BuildMasterMode())
.AddMode(BuildPbcMode())
+ .AddMode(BuildRemoteReplicaMode())
.AddMode(BuildTableMode())
.AddMode(BuildTabletMode())
+ .AddMode(BuildTServerMode())
.AddMode(BuildWalMode())
.Build();
http://git-wip-us.apache.org/repos/asf/kudu/blob/14cd22a1/src/kudu/tools/ts-cli.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/ts-cli.cc b/src/kudu/tools/ts-cli.cc
deleted file mode 100644
index f34adbf..0000000
--- a/src/kudu/tools/ts-cli.cc
+++ /dev/null
@@ -1,494 +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.
-//
-// Tool to query tablet server operational data
-
-#include <gflags/gflags.h>
-#include <glog/logging.h>
-#include <iostream>
-#include <memory>
-#include <strstream>
-
-#include "kudu/client/row_result.h"
-#include "kudu/client/scanner-internal.h"
-#include "kudu/common/partition.h"
-#include "kudu/common/schema.h"
-#include "kudu/common/wire_protocol.h"
-#include "kudu/gutil/strings/human_readable.h"
-#include "kudu/server/server_base.proxy.h"
-#include "kudu/tserver/tserver.pb.h"
-#include "kudu/tserver/tserver_admin.proxy.h"
-#include "kudu/tserver/tserver_service.proxy.h"
-#include "kudu/tserver/tablet_server.h"
-#include "kudu/util/env.h"
-#include "kudu/util/faststring.h"
-#include "kudu/util/flags.h"
-#include "kudu/util/logging.h"
-#include "kudu/util/net/net_util.h"
-#include "kudu/util/net/sockaddr.h"
-#include "kudu/rpc/messenger.h"
-#include "kudu/rpc/rpc_controller.h"
-
-using kudu::client::KuduRowResult;
-using kudu::HostPort;
-using kudu::rpc::Messenger;
-using kudu::rpc::MessengerBuilder;
-using kudu::rpc::RpcController;
-using kudu::server::ServerStatusPB;
-using kudu::Sockaddr;
-using kudu::client::KuduScanBatch;
-using kudu::tablet::TabletStatusPB;
-using kudu::tserver::DeleteTabletRequestPB;
-using kudu::tserver::DeleteTabletResponsePB;
-using kudu::tserver::ListTabletsRequestPB;
-using kudu::tserver::ListTabletsResponsePB;
-using kudu::tserver::NewScanRequestPB;
-using kudu::tserver::ScanRequestPB;
-using kudu::tserver::ScanResponsePB;
-using kudu::tserver::TabletServerAdminServiceProxy;
-using kudu::tserver::TabletServerServiceProxy;
-using std::ostringstream;
-using std::shared_ptr;
-using std::string;
-using std::vector;
-
-const char* const kListTabletsOp = "list_tablets";
-const char* const kAreTabletsRunningOp = "are_tablets_running";
-const char* const kSetFlagOp = "set_flag";
-const char* const kDumpTabletOp = "dump_tablet";
-const char* const kDeleteTabletOp = "delete_tablet";
-const char* const kCurrentTimestamp = "current_timestamp";
-const char* const kStatus = "status";
-
-DEFINE_string(server_address, "localhost",
- "Address of server to run against");
-DEFINE_int64(timeout_ms, 1000 * 60, "RPC timeout in milliseconds");
-
-DEFINE_bool(force, false, "If true, allows the set_flag command to set a flag "
- "which is not explicitly marked as runtime-settable. Such flag changes may be "
- "simply ignored on the server, or may cause the server to crash.");
-
-// Check that the value of argc matches what's expected, otherwise return a
-// non-zero exit code. Should be used in main().
-#define CHECK_ARGC_OR_RETURN_WITH_USAGE(op, expected) \
- do { \
- const string& _op = (op); \
- const int _expected = (expected); \
- if (argc != _expected) { \
- /* We substract 2 from _expected because we don't want to count argv[0] or [1]. */ \
- std::cerr << "Invalid number of arguments for " << _op \
- << ": expected " << (_expected - 2) << " arguments" << std::endl; \
- google::ShowUsageWithFlagsRestrict(argv[0], __FILE__); \
- return 2; \
- } \
- } while (0);
-
-// Invoke 'to_call' and check its result. If it failed, print 'to_prepend' and
-// the error to cerr and return a non-zero exit code. Should be used in main().
-#define RETURN_NOT_OK_PREPEND_FROM_MAIN(to_call, to_prepend) \
- do { \
- ::kudu::Status s = (to_call); \
- if (!s.ok()) { \
- std::cerr << (to_prepend) << ": " << s.ToString() << std::endl; \
- return 1; \
- } \
- } while (0);
-
-namespace kudu {
-namespace tools {
-
-typedef ListTabletsResponsePB::StatusAndSchemaPB StatusAndSchemaPB;
-
-class TsAdminClient {
- public:
- // Creates an admin client for host/port combination e.g.,
- // "localhost" or "127.0.0.1:7050".
- TsAdminClient(std::string addr, int64_t timeout_millis);
-
- // Initialized the client and connects to the specified tablet
- // server.
- Status Init();
-
- // Sets 'tablets' a list of status information for all tablets on a
- // given tablet server.
- Status ListTablets(std::vector<StatusAndSchemaPB>* tablets);
-
-
- // Sets the gflag 'flag' to 'val' on the remote server via RPC.
- // If 'force' is true, allows setting flags even if they're not marked as
- // safe to change at runtime.
- Status SetFlag(const string& flag, const string& val,
- bool force);
-
- // Get the schema for the given tablet.
- Status GetTabletSchema(const std::string& tablet_id, SchemaPB* schema);
-
- // Dump the contents of the given tablet, in key order, to the console.
- Status DumpTablet(const std::string& tablet_id);
-
- // Delete a tablet replica from the specified peer.
- // The 'reason' string is passed to the tablet server, used for logging.
- Status DeleteTablet(const std::string& tablet_id,
- const std::string& reason);
-
- // Sets timestamp to the value of the tablet server's current timestamp.
- Status CurrentTimestamp(uint64_t* timestamp);
-
- // Get the server status
- Status GetStatus(ServerStatusPB* pb);
- private:
- std::string addr_;
- vector<Sockaddr> addrs_;
- MonoDelta timeout_;
- bool initted_;
- shared_ptr<server::GenericServiceProxy> generic_proxy_;
- gscoped_ptr<tserver::TabletServerServiceProxy> ts_proxy_;
- gscoped_ptr<tserver::TabletServerAdminServiceProxy> ts_admin_proxy_;
- shared_ptr<rpc::Messenger> messenger_;
-
- DISALLOW_COPY_AND_ASSIGN(TsAdminClient);
-};
-
-TsAdminClient::TsAdminClient(string addr, int64_t timeout_millis)
- : addr_(std::move(addr)),
- timeout_(MonoDelta::FromMilliseconds(timeout_millis)),
- initted_(false) {}
-
-Status TsAdminClient::Init() {
- CHECK(!initted_);
-
- HostPort host_port;
- RETURN_NOT_OK(host_port.ParseString(addr_, tserver::TabletServer::kDefaultPort));
- MessengerBuilder builder("ts-cli");
- RETURN_NOT_OK(builder.Build(&messenger_));
-
- RETURN_NOT_OK(host_port.ResolveAddresses(&addrs_))
-
- generic_proxy_.reset(new server::GenericServiceProxy(messenger_, addrs_[0]));
- ts_proxy_.reset(new TabletServerServiceProxy(messenger_, addrs_[0]));
- ts_admin_proxy_.reset(new TabletServerAdminServiceProxy(messenger_, addrs_[0]));
-
- initted_ = true;
-
- VLOG(1) << "Connected to " << addr_;
-
- return Status::OK();
-}
-
-Status TsAdminClient::ListTablets(vector<StatusAndSchemaPB>* tablets) {
- CHECK(initted_);
-
- ListTabletsRequestPB req;
- ListTabletsResponsePB resp;
- RpcController rpc;
-
- rpc.set_timeout(timeout_);
- RETURN_NOT_OK(ts_proxy_->ListTablets(req, &resp, &rpc));
- if (resp.has_error()) {
- return StatusFromPB(resp.error().status());
- }
-
- tablets->assign(resp.status_and_schema().begin(), resp.status_and_schema().end());
-
- return Status::OK();
-}
-
-Status TsAdminClient::SetFlag(const string& flag, const string& val,
- bool force) {
- server::SetFlagRequestPB req;
- server::SetFlagResponsePB resp;
- RpcController rpc;
-
- rpc.set_timeout(timeout_);
- req.set_flag(flag);
- req.set_value(val);
- req.set_force(force);
-
- RETURN_NOT_OK(generic_proxy_->SetFlag(req, &resp, &rpc));
- switch (resp.result()) {
- case server::SetFlagResponsePB::SUCCESS:
- return Status::OK();
- case server::SetFlagResponsePB::NOT_SAFE:
- return Status::RemoteError(resp.msg() + " (use --force flag to allow anyway)");
- default:
- return Status::RemoteError(resp.ShortDebugString());
- }
-}
-
-Status TsAdminClient::GetTabletSchema(const std::string& tablet_id,
- SchemaPB* schema) {
- VLOG(1) << "Fetching schema for tablet " << tablet_id;
- vector<StatusAndSchemaPB> tablets;
- RETURN_NOT_OK(ListTablets(&tablets));
- for (const StatusAndSchemaPB& pair : tablets) {
- if (pair.tablet_status().tablet_id() == tablet_id) {
- *schema = pair.schema();
- return Status::OK();
- }
- }
- return Status::NotFound("Cannot find tablet", tablet_id);
-}
-
-Status TsAdminClient::DumpTablet(const std::string& tablet_id) {
- SchemaPB schema_pb;
- RETURN_NOT_OK(GetTabletSchema(tablet_id, &schema_pb));
- Schema schema;
- RETURN_NOT_OK(SchemaFromPB(schema_pb, &schema));
- kudu::client::KuduSchema client_schema(schema);
-
- ScanRequestPB req;
- ScanResponsePB resp;
-
- NewScanRequestPB* new_req = req.mutable_new_scan_request();
- RETURN_NOT_OK(SchemaToColumnPBs(
- schema, new_req->mutable_projected_columns(),
- SCHEMA_PB_WITHOUT_IDS | SCHEMA_PB_WITHOUT_STORAGE_ATTRIBUTES));
- new_req->set_tablet_id(tablet_id);
- new_req->set_cache_blocks(false);
- new_req->set_order_mode(ORDERED);
- new_req->set_read_mode(READ_AT_SNAPSHOT);
-
- do {
- RpcController rpc;
- rpc.set_timeout(timeout_);
- RETURN_NOT_OK_PREPEND(ts_proxy_->Scan(req, &resp, &rpc),
- "Scan() failed");
-
- if (resp.has_error()) {
- return Status::IOError("Failed to read: ", resp.error().ShortDebugString());
- }
-
- // The first response has a scanner ID. We use this for all subsequent
- // responses.
- if (resp.has_scanner_id()) {
- req.set_scanner_id(resp.scanner_id());
- req.clear_new_scan_request();
- }
- req.set_call_seq_id(req.call_seq_id() + 1);
-
- // Nothing to process from this scan result.
- if (!resp.has_data()) {
- continue;
- }
-
- KuduScanBatch::Data results;
- RETURN_NOT_OK(results.Reset(&rpc,
- &schema,
- &client_schema,
- make_gscoped_ptr(resp.release_data())));
- vector<KuduRowResult> rows;
- results.ExtractRows(&rows);
- for (const KuduRowResult& r : rows) {
- std::cout << r.ToString() << std::endl;
- }
- } while (resp.has_more_results());
- return Status::OK();
-}
-
-Status TsAdminClient::DeleteTablet(const string& tablet_id,
- const string& reason) {
- ServerStatusPB status_pb;
- RETURN_NOT_OK(GetStatus(&status_pb));
-
- DeleteTabletRequestPB req;
- DeleteTabletResponsePB resp;
- RpcController rpc;
-
- req.set_tablet_id(tablet_id);
- req.set_dest_uuid(status_pb.node_instance().permanent_uuid());
- req.set_reason(reason);
- req.set_delete_type(tablet::TABLET_DATA_TOMBSTONED);
- rpc.set_timeout(timeout_);
- RETURN_NOT_OK_PREPEND(ts_admin_proxy_->DeleteTablet(req, &resp, &rpc),
- "DeleteTablet() failed");
-
- if (resp.has_error()) {
- return Status::IOError("Failed to delete tablet: ",
- resp.error().ShortDebugString());
- }
- return Status::OK();
-}
-
-Status TsAdminClient::CurrentTimestamp(uint64_t* timestamp) {
- server::ServerClockRequestPB req;
- server::ServerClockResponsePB resp;
- RpcController rpc;
- rpc.set_timeout(timeout_);
- RETURN_NOT_OK(generic_proxy_->ServerClock(req, &resp, &rpc));
- CHECK(resp.has_timestamp()) << resp.DebugString();
- *timestamp = resp.timestamp();
- return Status::OK();
-}
-
-Status TsAdminClient::GetStatus(ServerStatusPB* pb) {
- server::GetStatusRequestPB req;
- server::GetStatusResponsePB resp;
- RpcController rpc;
- rpc.set_timeout(timeout_);
- RETURN_NOT_OK(generic_proxy_->GetStatus(req, &resp, &rpc));
- CHECK(resp.has_status()) << resp.DebugString();
- pb->Swap(resp.mutable_status());
- return Status::OK();
-}
-
-namespace {
-
-void SetUsage(const char* argv0) {
- ostringstream str;
-
- str << argv0 << " [--server_address=<addr>] <operation> <flags>\n"
- << "<operation> must be one of:\n"
- << " " << kListTabletsOp << "\n"
- << " " << kAreTabletsRunningOp << "\n"
- << " " << kSetFlagOp << " [-force] <flag> <value>\n"
- << " " << kDumpTabletOp << " <tablet_id>\n"
- << " " << kDeleteTabletOp << " <tablet_id> <reason string>\n"
- << " " << kCurrentTimestamp << "\n"
- << " " << kStatus;
- google::SetUsageMessage(str.str());
-}
-
-string GetOp(int argc, char** argv) {
- if (argc < 2) {
- google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
- exit(1);
- }
-
- return argv[1];
-}
-
-} // anonymous namespace
-
-static int TsCliMain(int argc, char** argv) {
- FLAGS_logtostderr = 1;
- SetUsage(argv[0]);
- ParseCommandLineFlags(&argc, &argv, true);
- InitGoogleLoggingSafe(argv[0]);
- const string addr = FLAGS_server_address;
-
- string op = GetOp(argc, argv);
-
- TsAdminClient client(addr, FLAGS_timeout_ms);
-
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.Init(),
- "Unable to establish connection to " + addr);
-
- // TODO add other operations here...
- if (op == kListTabletsOp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
-
- vector<StatusAndSchemaPB> tablets;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.ListTablets(&tablets),
- "Unable to list tablets on " + addr);
- for (const StatusAndSchemaPB& status_and_schema : tablets) {
- Schema schema;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(SchemaFromPB(status_and_schema.schema(), &schema),
- "Unable to deserialize schema from " + addr);
- PartitionSchema partition_schema;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(PartitionSchema::FromPB(status_and_schema.partition_schema(),
- schema, &partition_schema),
- "Unable to deserialize partition schema from " + addr);
-
-
- TabletStatusPB ts = status_and_schema.tablet_status();
-
- Partition partition;
- Partition::FromPB(ts.partition(), &partition);
-
- string state = tablet::TabletStatePB_Name(ts.state());
- std::cout << "Tablet id: " << ts.tablet_id() << std::endl;
- std::cout << "State: " << state << std::endl;
- std::cout << "Table name: " << ts.table_name() << std::endl;
- std::cout << "Partition: " << partition_schema.PartitionDebugString(partition, schema)
- << std::endl;
- if (ts.has_estimated_on_disk_size()) {
- std::cout << "Estimated on disk size: " <<
- HumanReadableNumBytes::ToString(ts.estimated_on_disk_size()) << std::endl;
- }
- std::cout << "Schema: " << schema.ToString() << std::endl;
- }
- } else if (op == kAreTabletsRunningOp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
-
- vector<StatusAndSchemaPB> tablets;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.ListTablets(&tablets),
- "Unable to list tablets on " + addr);
- bool all_running = true;
- for (const StatusAndSchemaPB& status_and_schema : tablets) {
- TabletStatusPB ts = status_and_schema.tablet_status();
- if (ts.state() != tablet::RUNNING) {
- std::cout << "Tablet id: " << ts.tablet_id() << " is "
- << tablet::TabletStatePB_Name(ts.state()) << std::endl;
- all_running = false;
- }
- }
-
- if (all_running) {
- std::cout << "All tablets are running" << std::endl;
- } else {
- std::cout << "Not all tablets are running" << std::endl;
- return 1;
- }
- } else if (op == kSetFlagOp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
-
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.SetFlag(argv[2], argv[3], FLAGS_force),
- "Unable to set flag");
-
- } else if (op == kDumpTabletOp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 3);
-
- string tablet_id = argv[2];
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.DumpTablet(tablet_id),
- "Unable to dump tablet");
- } else if (op == kDeleteTabletOp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 4);
-
- string tablet_id = argv[2];
- string reason = argv[3];
-
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.DeleteTablet(tablet_id, reason),
- "Unable to delete tablet");
- } else if (op == kCurrentTimestamp) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
-
- uint64_t timestamp;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.CurrentTimestamp(×tamp),
- "Unable to get timestamp");
- std::cout << timestamp << std::endl;
- } else if (op == kStatus) {
- CHECK_ARGC_OR_RETURN_WITH_USAGE(op, 2);
-
- ServerStatusPB status;
- RETURN_NOT_OK_PREPEND_FROM_MAIN(client.GetStatus(&status),
- "Unable to get status");
- std::cout << status.DebugString() << std::endl;
- } else {
- std::cerr << "Invalid operation: " << op << std::endl;
- google::ShowUsageWithFlagsRestrict(argv[0], __FILE__);
- return 2;
- }
-
- return 0;
-}
-
-} // namespace tools
-} // namespace kudu
-
-int main(int argc, char** argv) {
- return kudu::tools::TsCliMain(argc, argv);
-}