Skip to content

Commit

Permalink
tools: add a tool to extract an arbitrary block to stdout
Browse files Browse the repository at this point in the history
This allows a block to be dumped to stdout. I found this useful when
trying to see how compressible an index block was. We might also find
this useful for debugging block corruption issues on production
clusters -- it's much easier to extract a corrupted block and copy it
around than to try to copy an entire tablet or filesystem.

Change-Id: I04cf75169b1adb721791ca15b2d5ab5067025f06
Reviewed-on: http://gerrit.cloudera.org:8080/7260
Tested-by: Kudu Jenkins
Reviewed-by: Todd Lipcon <[email protected]>
  • Loading branch information
toddlipcon committed Jun 27, 2017
1 parent c19b8f4 commit 78ef92e
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
22 changes: 22 additions & 0 deletions src/kudu/tools/kudu-tool-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ TEST_F(ToolTest, TestModeHelp) {
}
{
const vector<string> kFsDumpModeRegexes = {
"block.*binary contents of a data block",
"cfile.*contents of a CFile",
"tree.*tree of a Kudu filesystem",
"uuid.*UUID of a Kudu filesystem"
Expand Down Expand Up @@ -818,6 +819,27 @@ TEST_F(ToolTest, TestFsDumpCFile) {
}
}

TEST_F(ToolTest, TestFsDumpBlock) {
const string kTestDir = GetTestPath("test");
FsManager fs(env_, kTestDir);
ASSERT_OK(fs.CreateInitialFileSystemLayout());
ASSERT_OK(fs.Open());

unique_ptr<WritableBlock> block;
ASSERT_OK(fs.CreateNewBlock({}, &block));
ASSERT_OK(block->Append("hello world"));
ASSERT_OK(block->Close());
BlockId block_id = block->id();

{
string stdout;
NO_FATALS(RunActionStdoutString(Substitute(
"fs dump block --fs_wal_dir=$0 $1",
kTestDir, block_id.ToString()), &stdout));
ASSERT_EQ("hello world", stdout);
}
}

TEST_F(ToolTest, TestWalDump) {
const string kTestDir = GetTestPath("test");
const string kTestTablet = "test-tablet";
Expand Down
53 changes: 51 additions & 2 deletions src/kudu/tools/tool_action_fs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,21 @@ Status DumpUuid(const RunnerContext& /*context*/) {
return Status::OK();
}

Status DumpCFile(const RunnerContext& context) {
Status ParseBlockIdArg(const RunnerContext& context,
BlockId* id) {
const string& block_id_str = FindOrDie(context.required_args, "block_id");
uint64_t numeric_id;
if (!safe_strtou64(block_id_str, &numeric_id)) {
return Status::InvalidArgument(Substitute(
"Could not parse $0 as numeric block ID", block_id_str));
}
BlockId block_id(numeric_id);
*id = BlockId(numeric_id);
return Status::OK();
}

Status DumpCFile(const RunnerContext& context) {
BlockId block_id;
RETURN_NOT_OK(ParseBlockIdArg(context, &block_id));

FsManagerOpts fs_opts;
fs_opts.read_only = true;
Expand Down Expand Up @@ -209,6 +216,35 @@ Status DumpCFile(const RunnerContext& context) {
return Status::OK();
}

Status DumpBlock(const RunnerContext& context) {
BlockId block_id;
RETURN_NOT_OK(ParseBlockIdArg(context, &block_id));

FsManagerOpts fs_opts;
fs_opts.read_only = true;
FsManager fs_manager(Env::Default(), fs_opts);
RETURN_NOT_OK(fs_manager.Open());

unique_ptr<fs::ReadableBlock> block;
RETURN_NOT_OK(fs_manager.OpenBlock(block_id, &block));

uint64_t size = 0;
RETURN_NOT_OK_PREPEND(block->Size(&size), "couldn't get block size");

faststring buf;
uint64_t offset = 0;
while (offset < size) {
int64_t chunk = std::min<int64_t>(size - offset, 64 * 1024);
buf.resize(chunk);
Slice s(buf);
RETURN_NOT_OK(block->Read(offset, &s));
offset += s.size();
cout << s.ToString();
}

return Status::OK();
}

Status DumpFsTree(const RunnerContext& /*context*/) {
FsManagerOpts fs_opts;
fs_opts.read_only = true;
Expand All @@ -225,13 +261,25 @@ static unique_ptr<Mode> BuildFsDumpMode() {
unique_ptr<Action> dump_cfile =
ActionBuilder("cfile", &DumpCFile)
.Description("Dump the contents of a CFile (column file)")
.ExtraDescription("This interprets the contents of a CFile-formatted block "
"and outputs the decoded row data.")
.AddRequiredParameter({ "block_id", "block identifier" })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.AddOptionalParameter("print_meta")
.AddOptionalParameter("print_rows")
.Build();

unique_ptr<Action> dump_block =
ActionBuilder("block", &DumpBlock)
.Description("Dump the binary contents of a data block")
.ExtraDescription("This performs no parsing or interpretation of the data stored "
"in the block but rather outputs its binary contents directly.")
.AddRequiredParameter({ "block_id", "block identifier" })
.AddOptionalParameter("fs_wal_dir")
.AddOptionalParameter("fs_data_dirs")
.Build();

unique_ptr<Action> dump_tree =
ActionBuilder("tree", &DumpFsTree)
.Description("Dump the tree of a Kudu filesystem")
Expand All @@ -248,6 +296,7 @@ static unique_ptr<Mode> BuildFsDumpMode() {

return ModeBuilder("dump")
.Description("Dump a Kudu filesystem")
.AddAction(std::move(dump_block))
.AddAction(std::move(dump_cfile))
.AddAction(std::move(dump_tree))
.AddAction(std::move(dump_uuid))
Expand Down

0 comments on commit 78ef92e

Please sign in to comment.