You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by gr...@apache.org on 2018/10/16 19:56:27 UTC
[3/5] kudu git commit: [tools] Add checking for row existence to the
locate_row tool
[tools] Add checking for row existence to the locate_row tool
This enhances the `kudu tablet locate_row` tool to that, in addition to
locating which tablet a row with a given primary key would end up in, it
also will check if the row actually exists when the -check_row_existence
flag is supplied. If the row does not exist, the tool returns an error;
if it does, it prints the row.
Example invocation:
$ bin/kudu table locate_row localhost:7053 default.loadgen_auto_49c97e85f6aa43b5a89723c7eee396b0 "[0]" -check_row_existence
850632cee25b43368cb6f226b53e76eb
(int64 key=0, int32 int_val=1, string string_val="2.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
Change-Id: I760d3fbb2e30a3ffba7143d3b51da6f3fd62b034
Reviewed-on: http://gerrit.cloudera.org:8080/11684
Tested-by: Will Berkeley <wd...@gmail.com>
Reviewed-by: Alexey Serbin <as...@cloudera.com>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/acf1dee8
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/acf1dee8
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/acf1dee8
Branch: refs/heads/master
Commit: acf1dee87ce347398ca86cc4959e38bf8794efe3
Parents: fa5a0db
Author: Will Berkeley <wd...@gmail.org>
Authored: Mon Oct 15 01:37:30 2018 -0700
Committer: Will Berkeley <wd...@gmail.com>
Committed: Tue Oct 16 19:41:54 2018 +0000
----------------------------------------------------------------------
src/kudu/tools/kudu-admin-test.cc | 70 ++++++++++++++++++++++++++++++++
src/kudu/tools/tool_action_table.cc | 29 +++++++++++++
2 files changed, 99 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/acf1dee8/src/kudu/tools/kudu-admin-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-admin-test.cc b/src/kudu/tools/kudu-admin-test.cc
index edb0c4d..d68fb4b 100644
--- a/src/kudu/tools/kudu-admin-test.cc
+++ b/src/kudu/tools/kudu-admin-test.cc
@@ -39,6 +39,7 @@
#include "kudu/client/client.h"
#include "kudu/client/schema.h"
#include "kudu/client/shared_ptr.h"
+#include "kudu/client/write_op.h"
#include "kudu/common/common.pb.h"
#include "kudu/common/partial_row.h"
#include "kudu/common/wire_protocol.pb.h"
@@ -79,8 +80,10 @@ DECLARE_int32(num_tablet_servers);
using kudu::client::KuduClient;
using kudu::client::KuduClientBuilder;
using kudu::client::KuduColumnSchema;
+using kudu::client::KuduInsert;
using kudu::client::KuduSchema;
using kudu::client::KuduSchemaBuilder;
+using kudu::client::KuduTable;
using kudu::client::KuduTableAlterer;
using kudu::client::KuduTableCreator;
using kudu::client::sp::shared_ptr;
@@ -1742,5 +1745,72 @@ TEST_F(AdminCliTest, TestLocateRowMore) {
ASSERT_STR_CONTAINS(stderr,
"Wrong type during field extraction: expected object array");
}
+
+TEST_F(AdminCliTest, TestLocateRowAndCheckRowPresence) {
+ FLAGS_num_tablet_servers = 1;
+ FLAGS_num_replicas = 1;
+
+ NO_FATALS(BuildAndStart());
+
+ // Grab list of tablet_ids from any tserver so we can check the output.
+ vector<TServerDetails*> tservers;
+ vector<string> tablet_ids;
+ AppendValuesFromMap(tablet_servers_, &tservers);
+ ListRunningTabletIds(tservers.front(),
+ MonoDelta::FromSeconds(30),
+ &tablet_ids);
+ ASSERT_EQ(1, tablet_ids.size());
+ const string& expected_tablet_id = tablet_ids[0];
+
+ // Test the case when the row does not exist.
+ string stdout, stderr;
+ Status s = RunKuduTool({
+ "table",
+ "locate_row",
+ cluster_->master()->bound_rpc_addr().ToString(),
+ kTableId,
+ "[0]",
+ "-check_row_existence",
+ }, &stdout, &stderr);
+ ASSERT_TRUE(s.IsRuntimeError()) << ToolRunInfo(s, stdout, stderr);
+ ASSERT_STR_CONTAINS(stdout, expected_tablet_id);
+ ASSERT_STR_CONTAINS(stderr, "row does not exist");
+
+ // Insert row with key = 0.
+ client::sp::shared_ptr<KuduClient> client;
+ CreateClient(&client);
+ client::sp::shared_ptr<KuduTable> table;
+ ASSERT_OK(client->OpenTable(kTableId, &table));
+ unique_ptr<KuduInsert> insert(table->NewInsert());
+ auto* row = insert->mutable_row();
+ ASSERT_OK(row->SetInt32("key", 0));
+ ASSERT_OK(row->SetInt32("int_val", 12345));
+ ASSERT_OK(row->SetString("string_val", "hello"));
+ const string row_str = row->ToString();
+ auto session = client->NewSession();
+ ASSERT_OK(session->Apply(insert.release()));
+ ASSERT_OK(session->Flush());
+ ASSERT_OK(session->Close());
+
+ // Test the case when the row exists. Since the scan is done by a subprocess
+ // using a different client instance, it's possible the scan will not
+ // immediately retrieve the row even though the write has already succeeded,
+ // so we ASSERT_EVENTUALLY.
+ ASSERT_EVENTUALLY([&]() {
+ stdout.clear();
+ stderr.clear();
+ s = RunKuduTool({
+ "table",
+ "locate_row",
+ cluster_->master()->bound_rpc_addr().ToString(),
+ kTableId,
+ "[0]",
+ "-check_row_existence",
+ }, &stdout, &stderr);
+ ASSERT_TRUE(s.ok()) << ToolRunInfo(s, stdout, stderr);
+ ASSERT_STR_CONTAINS(stdout, expected_tablet_id);
+ ASSERT_STR_CONTAINS(stdout, row_str);
+ });
+}
} // namespace tools
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/acf1dee8/src/kudu/tools/tool_action_table.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action_table.cc b/src/kudu/tools/tool_action_table.cc
index 30ce6a6..2156dba 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -38,6 +38,7 @@
#include "kudu/common/schema.h"
#include "kudu/gutil/map-util.h"
#include "kudu/gutil/stl_util.h"
+#include "kudu/gutil/strings/join.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/tools/tool_action.h"
@@ -46,6 +47,11 @@
#include "kudu/util/status.h"
DECLARE_string(tables);
+DEFINE_bool(check_row_existence, false,
+ "Also check for the existence of the row on the leader replica of "
+ "the tablet. If found, the full row will be printed; if not found, "
+ "an error message will be printed and the command will return a "
+ "non-zero status.");
DEFINE_bool(modify_external_catalogs, true,
"Whether to modify external catalogs, such as the Hive Metastore, "
"when renaming or dropping a table.");
@@ -59,6 +65,7 @@ using client::KuduClient;
using client::KuduClientBuilder;
using client::KuduColumnSchema;
using client::KuduPredicate;
+using client::KuduScanner;
using client::KuduScanToken;
using client::KuduScanTokenBuilder;
using client::KuduTable;
@@ -268,6 +275,8 @@ Status LocateRow(const RunnerContext& context) {
vector<KuduScanToken*> tokens;
ElementDeleter deleter(&tokens);
KuduScanTokenBuilder builder(table.get());
+ // In case we go on to check for existence of the row.
+ RETURN_NOT_OK(builder.SetSelection(KuduClient::ReplicaSelection::LEADER_ONLY));
for (auto& predicate : predicates) {
RETURN_NOT_OK(builder.AddConjunctPredicate(predicate.release()));
}
@@ -282,6 +291,25 @@ Status LocateRow(const RunnerContext& context) {
"all primary key columns specified but more than one matching tablet?");
}
cout << tokens[0]->tablet().id() << endl;
+
+ if (FLAGS_check_row_existence) {
+ KuduScanner* scanner_ptr;
+ RETURN_NOT_OK(tokens[0]->IntoKuduScanner(&scanner_ptr));
+ unique_ptr<KuduScanner> scanner(scanner_ptr);
+ vector<string> row_str;
+ RETURN_NOT_OK(ScanToStrings(scanner.get(), &row_str));
+ if (row_str.empty()) {
+ return Status::NotFound("row does not exist");
+ }
+ // There should be exactly one result, but if somehow there are more, print
+ // them all before returning an error.
+ cout << JoinStrings(row_str, "\n") << endl;
+ if (row_str.size() != 1) {
+ // This should be impossible.
+ return Status::IllegalState(
+ Substitute("expected 1 row but received $0", row_str.size()));
+ }
+ }
return Status::OK();
}
@@ -355,6 +383,7 @@ unique_ptr<Mode> BuildTableMode() {
.AddRequiredParameter({ kKeyArg,
"String representation of the row's primary key "
"as a JSON array" })
+ .AddOptionalParameter("check_row_existence")
.Build();
unique_ptr<Action> rename_column =