You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by da...@apache.org on 2016/08/10 06:06:25 UTC

[1/2] kudu git commit: Add table id to AlterTableResponsePB

Repository: kudu
Updated Branches:
  refs/heads/master acf093c18 -> 1dbfb7550


Add table id to AlterTableResponsePB

This also changes the Java client to take advantage of the ID to selectively
clear the table locations cache on range partitioning alteration.

Change-Id: I63402581fbdaef2abdf37910c1dfaedbdcba76e2
Reviewed-on: http://gerrit.cloudera.org:8080/3859
Reviewed-by: Adar Dembo <ad...@cloudera.com>
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/0f899ebd
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/0f899ebd
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/0f899ebd

Branch: refs/heads/master
Commit: 0f899ebd374aebbe17947b7842a559a4cf129feb
Parents: acf093c
Author: Dan Burkert <da...@cloudera.com>
Authored: Sun Aug 7 15:04:22 2016 -0700
Committer: Dan Burkert <da...@cloudera.com>
Committed: Wed Aug 10 06:06:06 2016 +0000

----------------------------------------------------------------------
 .../apache/kudu/client/AlterTableRequest.java   |  6 ++--
 .../apache/kudu/client/AlterTableResponse.java  | 12 +++++++-
 .../org/apache/kudu/client/AsyncKuduClient.java | 30 ++++++++++++++++----
 src/kudu/master/catalog_manager.cc              |  1 +
 src/kudu/master/master.proto                    |  4 +++
 5 files changed, 44 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/0f899ebd/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableRequest.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableRequest.java b/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableRequest.java
index 391e549..41eb1a1 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableRequest.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableRequest.java
@@ -69,8 +69,10 @@ class AlterTableRequest extends KuduRpc<AlterTableResponse> {
                                                 String tsUUID) throws Exception {
     final AlterTableResponsePB.Builder respBuilder = AlterTableResponsePB.newBuilder();
     readProtobuf(callResponse.getPBMessage(), respBuilder);
-    AlterTableResponse response = new AlterTableResponse(deadlineTracker.getElapsedMillis(),
-        tsUUID);
+    AlterTableResponse response = new AlterTableResponse(
+        deadlineTracker.getElapsedMillis(), tsUUID,
+        respBuilder.hasTableId() ? respBuilder.getTableId().toStringUtf8() : null);
+
     return new Pair<AlterTableResponse, Object>(
         response, respBuilder.hasError() ? respBuilder.getError() : null);
   }

http://git-wip-us.apache.org/repos/asf/kudu/blob/0f899ebd/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableResponse.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableResponse.java b/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableResponse.java
index 116816c..af582e1 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableResponse.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AlterTableResponse.java
@@ -23,10 +23,20 @@ import org.apache.kudu.annotations.InterfaceStability;
 @InterfaceStability.Evolving
 public class AlterTableResponse extends KuduRpcResponse {
 
+  private String tableId;
+
   /**
    * @param ellapsedMillis Time in milliseconds since RPC creation to now.
    */
-  AlterTableResponse(long ellapsedMillis, String tsUUID) {
+  AlterTableResponse(long ellapsedMillis, String tsUUID, String tableId) {
     super(ellapsedMillis, tsUUID);
+    this.tableId = tableId;
+  }
+
+  /**
+   * @return the ID of the altered table, or null if the master version is too old
+   */
+  public String getTableId() {
+    return tableId;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/kudu/blob/0f899ebd/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
index 2b0cb75..70b06ed 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
@@ -354,18 +354,36 @@ public class AsyncKuduClient implements AutoCloseable {
 
     if (ato.hasAddDropRangePartitions()) {
       // Clear the table locations cache so the new partition is immediately visible.
-      Callback clearCacheCB = new Callback() {
+      return response.addCallback(new Callback<AlterTableResponse, AlterTableResponse>() {
         @Override
-        public Object call(Object resp) throws Exception {
-          tableLocations.clear();
+        public AlterTableResponse call(AlterTableResponse resp) {
+          // If the master is of a recent enough version to return the table ID,
+          // we can selectively clear the cache only for the altered table.
+          // Otherwise, we clear the caches for all tables.
+          if (resp.getTableId() != null) {
+            tableLocations.remove(resp.getTableId());
+          } else {
+            tableLocations.clear();
+          }
           return resp;
         }
         @Override
         public String toString() {
-          return "ClearCacheCB";
+          return "ClearTableLocationsCacheCB";
+        }
+      }).addErrback(new Callback<Exception, Exception>() {
+        @Override
+        public Exception call(Exception e) {
+          // We clear the cache even on failure, just in
+          // case the alter table operation actually succeeded.
+          tableLocations.clear();
+          return e;
+        }
+        @Override
+        public String toString() {
+          return "ClearTableLocationsCacheEB";
         }
-      };
-      return response.addCallback(clearCacheCB).addErrback(clearCacheCB);
+      });
     }
     return response;
   }

http://git-wip-us.apache.org/repos/asf/kudu/blob/0f899ebd/src/kudu/master/catalog_manager.cc
----------------------------------------------------------------------
diff --git a/src/kudu/master/catalog_manager.cc b/src/kudu/master/catalog_manager.cc
index e22fb47..e2061d9 100644
--- a/src/kudu/master/catalog_manager.cc
+++ b/src/kudu/master/catalog_manager.cc
@@ -1428,6 +1428,7 @@ Status CatalogManager::AlterTable(const AlterTableRequestPB* req,
   }
 
   string table_name = l.data().name();
+  *resp->mutable_table_id() = table->id();
 
   // 4. Calculate new schema for the on-disk state, not persisted yet.
   Schema new_schema;

http://git-wip-us.apache.org/repos/asf/kudu/blob/0f899ebd/src/kudu/master/master.proto
----------------------------------------------------------------------
diff --git a/src/kudu/master/master.proto b/src/kudu/master/master.proto
index cae4dae..5b207a2 100644
--- a/src/kudu/master/master.proto
+++ b/src/kudu/master/master.proto
@@ -486,7 +486,11 @@ message AlterTableResponsePB {
   // The error, if an error occurred with this request.
   optional MasterErrorPB error = 1;
 
+  // The schema version of the altered table.
   optional uint32 schema_version = 2;
+
+  // The table ID of the altered table.
+  optional bytes table_id = 3;
 }
 
 message IsAlterTableDoneRequestPB {


[2/2] kudu git commit: Fix bug in partition key debug printing

Posted by da...@apache.org.
Fix bug in partition key debug printing

This fixes a bug in compound-column range partition key debug printing. Also
adds a test for range partition encoding with compound columns.

Change-Id: Idac701428a9af03605cd1a156926bdbd1a5f5fac
Reviewed-on: http://gerrit.cloudera.org:8080/3879
Reviewed-by: Adar Dembo <ad...@cloudera.com>
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/1dbfb755
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/1dbfb755
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/1dbfb755

Branch: refs/heads/master
Commit: 1dbfb75508040824cc261b1c9127c86727d42087
Parents: 0f899eb
Author: Dan Burkert <da...@cloudera.com>
Authored: Tue Aug 9 19:03:02 2016 -0700
Committer: Dan Burkert <da...@cloudera.com>
Committed: Wed Aug 10 06:06:12 2016 +0000

----------------------------------------------------------------------
 src/kudu/common/partition-test.cc | 106 ++++++++++++++++++++++++++-------
 src/kudu/common/partition.cc      |  51 +++++++---------
 src/kudu/common/partition.h       |  11 +---
 3 files changed, 110 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/1dbfb755/src/kudu/common/partition-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/common/partition-test.cc b/src/kudu/common/partition-test.cc
index 11c93e7..1600e3f 100644
--- a/src/kudu/common/partition-test.cc
+++ b/src/kudu/common/partition-test.cc
@@ -122,6 +122,76 @@ void CheckCreateRangePartitions(const vector<pair<optional<string>, optional<str
 
 } // namespace
 
+// Tests that missing values are correctly filled in with minimums when creating
+// range partition keys, and that completely missing keys are encoded as the
+// logical minimum and logical maximum for lower and upper bounds, respectively.
+TEST(PartitionTest, TestCompoundRangeKeyEncoding) {
+
+  // CREATE TABLE t (c1 STRING, c2 STRING, c3 STRING),
+  // PRIMARY KEY (c1, c2, c3)
+  // PARITITION BY RANGE (c1, c2, c3);
+  Schema schema({ ColumnSchema("c1", STRING),
+                  ColumnSchema("c2", STRING),
+                  ColumnSchema("c3", STRING) },
+                { ColumnId(0), ColumnId(1), ColumnId(2) }, 3);
+
+  PartitionSchemaPB schema_builder;
+  PartitionSchema partition_schema;
+  ASSERT_OK(PartitionSchema::FromPB(schema_builder, schema, &partition_schema));
+
+  ASSERT_EQ("range columns: [c1, c2, c3]", partition_schema.DebugString(schema));
+
+  vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
+  vector<KuduPartialRow> splits;
+
+  { // [(_, _, _), (_, _, b))
+    KuduPartialRow lower(&schema);
+    KuduPartialRow upper(&schema);
+    ASSERT_OK(upper.SetStringCopy("c3", "b"));
+    bounds.emplace_back(std::move(lower), std::move(upper));
+  }
+
+  { // [(_, b, c), (d, _, f))
+    KuduPartialRow lower(&schema);
+    KuduPartialRow upper(&schema);
+    ASSERT_OK(lower.SetStringCopy("c2", "b"));
+    ASSERT_OK(lower.SetStringCopy("c3", "c"));
+    ASSERT_OK(upper.SetStringCopy("c1", "d"));
+    ASSERT_OK(upper.SetStringCopy("c3", "f"));
+    bounds.emplace_back(std::move(lower), std::move(upper));
+  }
+
+  { // [(e, _, _), (_, _, _))
+    KuduPartialRow lower(&schema);
+    KuduPartialRow upper(&schema);
+    ASSERT_OK(lower.SetStringCopy("c1", "e"));
+    bounds.emplace_back(std::move(lower), std::move(upper));
+  }
+
+  { // split: (_, _, a)
+    KuduPartialRow split(&schema);
+    ASSERT_OK(split.SetStringCopy("c3", "a"));
+    splits.emplace_back(std::move(split));
+  }
+
+  vector<Partition> partitions;
+  ASSERT_OK(partition_schema.CreatePartitions(splits, bounds, schema, &partitions));
+  ASSERT_EQ(4, partitions.size());
+
+  EXPECT_TRUE(partitions[0].hash_buckets().empty());
+
+  EXPECT_EQ("range: [(<start>), (string c1=, string c2=, string c3=a))",
+            partition_schema.PartitionDebugString(partitions[0], schema));
+  EXPECT_EQ("range: [(string c1=, string c2=, string c3=a), "
+                    "(string c1=, string c2=, string c3=b))",
+            partition_schema.PartitionDebugString(partitions[1], schema));
+  EXPECT_EQ("range: [(string c1=, string c2=b, string c3=c), "
+            "(string c1=d, string c2=, string c3=f))",
+            partition_schema.PartitionDebugString(partitions[2], schema));
+  EXPECT_EQ("range: [(string c1=e, string c2=, string c3=), (<end>))",
+            partition_schema.PartitionDebugString(partitions[3], schema));
+}
+
 TEST(PartitionTest, TestPartitionKeyEncoding) {
   // CREATE TABLE t (a INT32, b VARCHAR, c VARCHAR, PRIMARY KEY (a, b, c))
   // PARITITION BY [HASH BUCKET (a, b), HASH BUCKET (c), RANGE (a, b, c)];
@@ -440,8 +510,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("a1\0\0b1\0\0c1", 10), partitions[0].range_key_end());
   EXPECT_EQ(string("", 0), partitions[0].partition_key_start());
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a1\0\0b1\0\0c1", 18), partitions[0].partition_key_end());
-  EXPECT_EQ("hash buckets: (0, 0), "
-            "range: [(<start>), (string a=a1, string b=b1, string c=c1))",
+  EXPECT_EQ("hash buckets: (0, 0), range: [(<start>), (string a=a1, string b=b1, string c=c1))",
             partition_schema.PartitionDebugString(partitions[0], schema));
 
   EXPECT_EQ(0, partitions[1].hash_buckets()[0]);
@@ -451,8 +520,8 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a1\0\0b1\0\0c1", 18),
             partitions[1].partition_key_start());
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a2\0\0b2\0\0", 16), partitions[1].partition_key_end());
-  EXPECT_EQ("hash buckets: (0, 0), "
-            "range: [(string a=a1, string b=b1, string c=c1), (string a=a2, string b=b2, <end>))",
+  EXPECT_EQ("hash buckets: (0, 0), range: [(string a=a1, string b=b1, string c=c1), "
+                                          "(string a=a2, string b=b2, string c=))",
             partition_schema.PartitionDebugString(partitions[1], schema));
 
   EXPECT_EQ(0, partitions[2].hash_buckets()[0]);
@@ -462,7 +531,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a2\0\0b2\0\0", 16), partitions[2].partition_key_start());
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1", 8), partitions[2].partition_key_end());
   EXPECT_EQ("hash buckets: (0, 0), "
-            "range: [(string a=a2, string b=b2, <start>), (<end>))",
+            "range: [(string a=a2, string b=b2, string c=), (<end>))",
             partition_schema.PartitionDebugString(partitions[2], schema));
 
   EXPECT_EQ(0, partitions[3].hash_buckets()[0]);
@@ -482,8 +551,8 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a1\0\0b1\0\0c1", 18),
             partitions[4].partition_key_start());
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a2\0\0b2\0\0", 16), partitions[4].partition_key_end());
-  EXPECT_EQ("hash buckets: (0, 1), "
-            "range: [(string a=a1, string b=b1, string c=c1), (string a=a2, string b=b2, <end>))",
+  EXPECT_EQ("hash buckets: (0, 1), range: [(string a=a1, string b=b1, string c=c1), "
+                                          "(string a=a2, string b=b2, string c=))",
             partition_schema.PartitionDebugString(partitions[4], schema));
 
   EXPECT_EQ(0, partitions[5].hash_buckets()[0]);
@@ -492,8 +561,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("", 0), partitions[5].range_key_end());
   EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a2\0\0b2\0\0", 16), partitions[5].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1", 4), partitions[5].partition_key_end());
-  EXPECT_EQ("hash buckets: (0, 1), "
-            "range: [(string a=a2, string b=b2, <start>), (<end>))",
+  EXPECT_EQ("hash buckets: (0, 1), range: [(string a=a2, string b=b2, string c=), (<end>))",
             partition_schema.PartitionDebugString(partitions[5], schema));
 
   EXPECT_EQ(1, partitions[6].hash_buckets()[0]);
@@ -502,8 +570,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("a1\0\0b1\0\0c1", 10), partitions[6].range_key_end());
   EXPECT_EQ(string("\0\0\0\1", 4), partitions[6].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a1\0\0b1\0\0c1", 18), partitions[6].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 0), "
-            "range: [(<start>), (string a=a1, string b=b1, string c=c1))",
+  EXPECT_EQ("hash buckets: (1, 0), range: [(<start>), (string a=a1, string b=b1, string c=c1))",
             partition_schema.PartitionDebugString(partitions[6], schema));
 
   EXPECT_EQ(1, partitions[7].hash_buckets()[0]);
@@ -513,8 +580,8 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a1\0\0b1\0\0c1", 18),
             partitions[7].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a2\0\0b2\0\0", 16), partitions[7].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 0), "
-            "range: [(string a=a1, string b=b1, string c=c1), (string a=a2, string b=b2, <end>))",
+  EXPECT_EQ("hash buckets: (1, 0), range: [(string a=a1, string b=b1, string c=c1), "
+                                          "(string a=a2, string b=b2, string c=))",
             partition_schema.PartitionDebugString(partitions[7], schema));
 
   EXPECT_EQ(1, partitions[8].hash_buckets()[0]);
@@ -523,8 +590,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("", 0), partitions[8].range_key_end());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a2\0\0b2\0\0", 16), partitions[8].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1", 8), partitions[8].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 0), "
-            "range: [(string a=a2, string b=b2, <start>), (<end>))",
+  EXPECT_EQ("hash buckets: (1, 0), range: [(string a=a2, string b=b2, string c=), (<end>))",
             partition_schema.PartitionDebugString(partitions[8], schema));
 
   EXPECT_EQ(1, partitions[9].hash_buckets()[0]);
@@ -533,8 +599,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("a1\0\0b1\0\0c1", 10), partitions[9].range_key_end());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1", 8), partitions[9].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a1\0\0b1\0\0c1", 18), partitions[9].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 1), "
-            "range: [(<start>), (string a=a1, string b=b1, string c=c1))",
+  EXPECT_EQ("hash buckets: (1, 1), range: [(<start>), (string a=a1, string b=b1, string c=c1))",
             partition_schema.PartitionDebugString(partitions[9], schema));
 
   EXPECT_EQ(1, partitions[10].hash_buckets()[0]);
@@ -544,8 +609,8 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a1\0\0b1\0\0c1", 18),
             partitions[10].partition_key_start());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a2\0\0b2\0\0", 16), partitions[10].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 1), "
-            "range: [(string a=a1, string b=b1, string c=c1), (string a=a2, string b=b2, <end>))",
+  EXPECT_EQ("hash buckets: (1, 1), range: [(string a=a1, string b=b1, string c=c1), "
+                                          "(string a=a2, string b=b2, string c=))",
             partition_schema.PartitionDebugString(partitions[10], schema));
 
   EXPECT_EQ(1, partitions[11].hash_buckets()[0]);
@@ -554,8 +619,7 @@ TEST(PartitionTest, TestCreatePartitions) {
   EXPECT_EQ(string("", 0), partitions[11].range_key_end());
   EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a2\0\0b2\0\0", 16), partitions[11].partition_key_start());
   EXPECT_EQ(string("", 0), partitions[11].partition_key_end());
-  EXPECT_EQ("hash buckets: (1, 1), "
-            "range: [(string a=a2, string b=b2, <start>), (<end>))",
+  EXPECT_EQ("hash buckets: (1, 1), range: [(string a=a2, string b=b2, string c=), (<end>))",
             partition_schema.PartitionDebugString(partitions[11], schema));
 }
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/1dbfb755/src/kudu/common/partition.cc
----------------------------------------------------------------------
diff --git a/src/kudu/common/partition.cc b/src/kudu/common/partition.cc
index d1a7733..e89000f 100644
--- a/src/kudu/common/partition.cc
+++ b/src/kudu/common/partition.cc
@@ -279,9 +279,11 @@ Status PartitionSchema::EncodeRangeBounds(const vector<pair<KuduPartialRow,
     if (first_upper.empty() || second_lower.empty() || first_upper > second_lower) {
       return Status::InvalidArgument(
           "overlapping range bounds",
-          strings::Substitute("first upper bound: ($0), second lower bound: ($1)",
-                              RangeKeyDebugString(first_upper, schema),
-                              RangeKeyDebugString(second_lower, schema)));
+          strings::Substitute("first bound: [($0), ($1)), second bound: [($2), ($3))",
+                              RangeKeyDebugString(range_partitions->at(i).first, schema),
+                              RangeKeyDebugString(range_partitions->at(i).second, schema),
+                              RangeKeyDebugString(range_partitions->at(i + 1).first, schema),
+                              RangeKeyDebugString(range_partitions->at(i + 1).second, schema)));
     }
   }
 
@@ -549,24 +551,32 @@ string PartitionSchema::PartitionDebugString(const Partition& partition,
 
     s.append("range: [(");
 
-    vector<string> start_components;
     Slice encoded_range_key_start = partition.range_key_start();
     Status status;
     status = DecodeRangeKey(&encoded_range_key_start, &start_row, &arena);
     if (status.ok()) {
-      AppendRangeDebugStringComponentsOrString(start_row, "<start>", &start_components);
-      s.append(JoinStrings(start_components, ", "));
+      if (IsRangePartitionKeyEmpty(start_row)) {
+        s.append("<start>");
+      } else {
+        vector<string> start_components;
+        AppendRangeDebugStringComponentsOrMin(start_row, &start_components);
+        s.append(JoinStrings(start_components, ", "));
+      }
     } else {
       s.append(Substitute("<decode-error: $0>", status.ToString()));
     }
     s.append("), (");
 
-    vector<string> end_components;
     Slice encoded_range_key_end = partition.range_key_end();
     status = DecodeRangeKey(&encoded_range_key_end, &end_row, &arena);
     if (status.ok()) {
-      AppendRangeDebugStringComponentsOrString(end_row, "<end>", &end_components);
-      s.append(JoinStrings(end_components, ", "));
+      if (IsRangePartitionKeyEmpty(end_row)) {
+        s.append("<end>");
+      } else {
+        vector<string> end_components;
+        AppendRangeDebugStringComponentsOrMin(end_row, &end_components);
+        s.append(JoinStrings(end_components, ", "));
+      }
     } else {
       s.append(Substitute("<decode-error: $0>", status.ToString()));
     }
@@ -576,29 +586,12 @@ string PartitionSchema::PartitionDebugString(const Partition& partition,
   return s;
 }
 
-void PartitionSchema::AppendRangeDebugStringComponentsOrString(const KuduPartialRow& row,
-                                                               const StringPiece default_string,
-                                                               vector<string>* components) const {
+bool PartitionSchema::IsRangePartitionKeyEmpty(const KuduPartialRow& row) const {
   ConstContiguousRow const_row(row.schema(), row.row_data_);
-
   for (ColumnId column_id : range_schema_.column_ids) {
-    string column;
-    int32_t column_idx = row.schema()->find_column_by_id(column_id);
-    if (column_idx == Schema::kColumnNotFound) {
-      components->push_back("<unknown-column>");
-      continue;
-    }
-    const ColumnSchema& column_schema = row.schema()->column(column_idx);
-
-    if (!row.IsColumnSet(column_idx)) {
-      components->push_back(default_string.as_string());
-      break;
-    } else {
-      column_schema.DebugCellAppend(const_row.cell(column_idx), &column);
-    }
-
-    components->push_back(column);
+    if (row.IsColumnSet(row.schema()->find_column_by_id(column_id))) return false;
   }
+  return true;
 }
 
 void PartitionSchema::AppendRangeDebugStringComponentsOrMin(const KuduPartialRow& row,

http://git-wip-us.apache.org/repos/asf/kudu/blob/1dbfb755/src/kudu/common/partition.h
----------------------------------------------------------------------
diff --git a/src/kudu/common/partition.h b/src/kudu/common/partition.h
index 1466934..347d809 100644
--- a/src/kudu/common/partition.h
+++ b/src/kudu/common/partition.h
@@ -237,14 +237,9 @@ class PartitionSchema {
   template<typename Row>
   Status EncodeKeyImpl(const Row& row, string* buf) const;
 
-  // Appends the stringified range partition components of a partial row to a
-  // vector.
-  //
-  // If any columns of the range partition do not exist in the partial row,
-  // processing stops and the provided default string piece is appended to the vector.
-  void AppendRangeDebugStringComponentsOrString(const KuduPartialRow& row,
-                                                StringPiece default_string,
-                                                std::vector<std::string>* components) const;
+  // Returns true if all of the columns in the range partition key are unset in
+  // the row.
+  bool IsRangePartitionKeyEmpty(const KuduPartialRow& row) const;
 
   // Appends the stringified range partition components of a partial row to a
   // vector.