This is an automated email from the ASF dual-hosted git repository.
alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push:
new 0345190 KUDU-2671 allow a range to have empty hash schema
0345190 is described below
commit 03451904a20123ca27eaa4e9773b94c0532fd342
Author: Alexey Serbin <[email protected]>
AuthorDate: Mon Aug 30 22:03:23 2021 -0700
KUDU-2671 allow a range to have empty hash schema
With this patch, the semantics of an empty hash schema for a range
changes. Now an empty per-range hash schema means no hash bucketing for
the range. Prior to this patch, an empty hash schema for a range meant
using the table-wide hash schema.
The new semantics are better because:
* they allow for having ranges with no hash bucketing even if there is
a non-trivial hash bucketing at the table-wide level
* they are less surprising to a user of the client API
This patch updates several test cases to account for the change and
adds a new test case to cover the new functionality.
Change-Id: Ia43df69ecd7040e285e098fde49d84a7a00d1fbb
Reviewed-on: http://gerrit.cloudera.org:8080/17825
Tested-by: Kudu Jenkins
Reviewed-by: Andrew Wong <[email protected]>
Reviewed-by: Mahesh Reddy <[email protected]>
---
src/kudu/client/client.cc | 8 +-
src/kudu/client/client.h | 25 +-
src/kudu/client/flex_partitioning_client-test.cc | 61 +++-
src/kudu/client/table_creator-internal.cc | 3 +-
src/kudu/client/table_creator-internal.h | 1 +
src/kudu/common/partition-test.cc | 67 ++---
src/kudu/common/partition.cc | 50 ++--
src/kudu/common/partition_pruner-test.cc | 316 ++++++++++-----------
src/kudu/common/partition_pruner.cc | 3 +-
.../integration-tests/table_locations-itest.cc | 5 +-
10 files changed, 271 insertions(+), 268 deletions(-)
diff --git a/src/kudu/client/client.cc b/src/kudu/client/client.cc
index a6c12d0..1ed91fa 100644
--- a/src/kudu/client/client.cc
+++ b/src/kudu/client/client.cc
@@ -879,8 +879,12 @@ KuduTableCreator& KuduTableCreator::add_range_partition(
KuduPartialRow* upper_bound,
RangePartitionBound lower_bound_type,
RangePartitionBound upper_bound_type) {
- data_->range_partitions_.emplace_back(new KuduRangePartition(
+ unique_ptr<KuduRangePartition> range_partition(new KuduRangePartition(
lower_bound, upper_bound, lower_bound_type, upper_bound_type));
+ // Using KuduTableCreator::add_range_partition() assumes the range partition
+ // uses the table-wide schema.
+ range_partition->data_->is_table_wide_hash_schema_ = true;
+ data_->range_partitions_.emplace_back(std::move(range_partition));
return *this;
}
@@ -1006,7 +1010,7 @@ Status KuduTableCreator::Create() {
RowOperationsPBEncoder encoder(range_pb->mutable_range_bounds());
encoder.Add(lower_bound_type, *range->lower_bound_);
encoder.Add(upper_bound_type, *range->upper_bound_);
- if (range->hash_schema_.empty()) {
+ if (range->is_table_wide_hash_schema_) {
// With the presence of a range with custom hash schema when the
// table-wide hash schema is used for this particular range, also add
an
// element into PartitionSchemaPB::custom_hash_schema_ranges to satisfy
diff --git a/src/kudu/client/client.h b/src/kudu/client/client.h
index 4e51a9e..ea7638b 100644
--- a/src/kudu/client/client.h
+++ b/src/kudu/client/client.h
@@ -1216,7 +1216,7 @@ class KUDU_EXPORT KuduTableCreator {
/// A helper class to represent a Kudu range partition with a custom hash
/// bucket schema. The hash sub-partitioning for a range partition might be
/// different from the default table-wide hash bucket schema specified during
- /// a table's creation (see KuduTableCreator::add_hash_partitions()).
+ /// the creation of a table (see KuduTableCreator::add_hash_partitions()).
/// Correspondingly, this class provides a means to specify a custom hash
/// bucket structure for the data in a range partition.
class KuduRangePartition {
@@ -1242,13 +1242,16 @@ class KUDU_EXPORT KuduTableCreator {
~KuduRangePartition();
- /// Add an extra level of hash partitioning for this range partition.
+ /// Add a level of hash sub-partitioning for this range partition.
///
- /// The newly added hash partitioning level is defined by its hash bucket
- /// schema. The hash bucket schema is specified by the parameters of this
- /// method. A range partition can have multiple levels of hash
partitioning,
- /// i.e. this method can be called multiple times to establish a
- /// multi-dimensional hash bucket structure for the range partition.
+ /// The hash schema for the range partition is defined by the whole set of
+ /// its hash sub-partitioning levels. A range partition can have multiple
+ /// levels of hash sub-partitioning: this method can be called multiple
+ /// times to define a multi-dimensional hash bucketing structure for the
+ /// range. Alternatively, a range partition can have zero levels of hash
+ /// sub-partitioning: simply don't call this method on a newly created
+ /// @c KuduRangePartition object to have no hash sub-partitioning for the
+ /// range represented by the object.
///
/// @param [in] columns
/// Names of columns to use for partitioning.
@@ -1306,7 +1309,13 @@ class KUDU_EXPORT KuduTableCreator {
/// Add a range partition with a custom hash bucket schema.
///
/// This method allows adding a range partition which has hash partitioning
- /// schema different from the schema used for a range partition.
+ /// schema different from the table-wide one.
+ ///
+ /// @li When called with a @c KuduRangePartition for which
+ /// @c KuduRangePartition::add_hash_partitions() hasn't been called,
+ /// a range with no hash sub-partitioning is created.
+ /// @li To create a range with the table-wide hash schema, use
+ /// @c KuduTableCreator::add_range_partition() instead.
///
/// @warning This functionality isn't fully implemented yet.
///
diff --git a/src/kudu/client/flex_partitioning_client-test.cc
b/src/kudu/client/flex_partitioning_client-test.cc
index a2ab310..cc00baa 100644
--- a/src/kudu/client/flex_partitioning_client-test.cc
+++ b/src/kudu/client/flex_partitioning_client-test.cc
@@ -270,7 +270,7 @@ class FlexPartitioningCreateTableTest : public
FlexPartitioningTest {};
// TODO(aserbin): add verification based on PartitionSchema provided by
// KuduTable::partition_schema() once PartitionPruner
// recognized custom hash bucket schema for ranges
-TEST_F(FlexPartitioningCreateTableTest, CustomHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, CustomHashSchema) {
// One-level hash bucket structure: { 3, "key" }.
{
constexpr const char* const kTableName = "3@key";
@@ -285,14 +285,14 @@ TEST_F(FlexPartitioningCreateTableTest,
CustomHashBuckets) {
}
}
-TEST_F(FlexPartitioningCreateTableTest, TableWideHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, TableWideHashSchema) {
// Create a table with the following partitions:
//
// hash bucket
// key 0 1
// -------------------------
// <111 x:{key} x:{key}
- constexpr const char* const kTableName = "TableWideHashBuckets";
+ constexpr const char* const kTableName = "TableWideHashSchema";
unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
table_creator->table_name(kTableName)
@@ -316,6 +316,38 @@ TEST_F(FlexPartitioningCreateTableTest,
TableWideHashBuckets) {
NO_FATALS(CheckTableRowsNum(kTableName, 222));
}
+TEST_F(FlexPartitioningCreateTableTest, EmptyTableWideHashSchema) {
+ constexpr const char* const kTableName = "EmptyTableWideHashSchema";
+
+ unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
+ table_creator->table_name(kTableName)
+ .schema(&schema_)
+ .num_replicas(1)
+ .set_range_partition_columns({ kKeyColumn });
+
+ // Add a range partition with the table-wide hash partitioning rules: no hash
+ // bucketing at all.
+ {
+ unique_ptr<KuduPartialRow> lower(schema_.NewRow());
+ ASSERT_OK(lower->SetInt32(kKeyColumn, INT32_MIN));
+ unique_ptr<KuduPartialRow> upper(schema_.NewRow());
+ ASSERT_OK(upper->SetInt32(kKeyColumn, 111));
+ table_creator->add_range_partition(lower.release(), upper.release());
+ }
+
+ // Add a custom range: no hash bucketing as well.
+ {
+ auto p = CreateRangePartition(111, 222);
+ table_creator->add_custom_range_partition(p.release());
+ }
+
+ ASSERT_OK(table_creator->Create());
+ // There should be 2 tablets total: one per each range created.
+ NO_FATALS(CheckTabletCount(kTableName, 2));
+ ASSERT_OK(InsertTestRows(kTableName, -111, 222, KuduSession::MANUAL_FLUSH));
+ NO_FATALS(CheckTableRowsNum(kTableName, 333));
+}
+
// Create a table with mixed set of range partitions, using both table-wide and
// custom hash bucket schemas.
//
@@ -323,7 +355,7 @@ TEST_F(FlexPartitioningCreateTableTest,
TableWideHashBuckets) {
// KuduTable::partition_schema() once PartitionPruner
// recognized custom hash bucket schema for ranges
// TODO(aserbin): add InsertTestRows() when proper key encoding is implemented
-TEST_F(FlexPartitioningCreateTableTest, DefaultAndCustomHashBuckets) {
+TEST_F(FlexPartitioningCreateTableTest, DefaultAndCustomHashSchemas) {
// Create a table with the following partitions:
//
// hash bucket
@@ -333,8 +365,8 @@ TEST_F(FlexPartitioningCreateTableTest,
DefaultAndCustomHashBuckets) {
// 111-222 x:{key} x:{key} x:{key} -
// 222-333 x:{key} x:{key} x:{key} x:{key}
// 333-444 x:{key} x:{key} - -
- // 444-555 x:{key} x:{key} - -
- constexpr const char* const kTableName = "DefaultAndCustomHashBuckets";
+ // 444-555 - - - -
+ constexpr const char* const kTableName = "DefaultAndCustomHashSchemas";
unique_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
table_creator->table_name(kTableName)
@@ -376,18 +408,21 @@ TEST_F(FlexPartitioningCreateTableTest,
DefaultAndCustomHashBuckets) {
table_creator->add_custom_range_partition(p.release());
}
- // Add a range partition with table-wide hash schema: not calling
- // KuduRangePartition::add_hash_partition() means the range is using the
- // table-wide schema.
- //
- // TODO(aserbin): update this once empty range schema means no hash bucketing
+ // Add a range partition with no hash bucketing. The table-wide hash schema
+ // established by the KuduTableCreator::add_hash_partition() call in the
+ // beginning of the scenario defines hash bucketing for ranges added by the
+ // KuduTableCreator::add_range_partition() method, but here the newly created
+ // range is added via the KuduTableCreator::add_custom_range_partition()
call,
+ // so the new range has custom hash schema. Not calling
+ // KuduRangePartition::add_hash_partitions() on the newly created range means
+ // the range doesn't have any hash bucketing.
{
auto p = CreateRangePartition(444, 555);
table_creator->add_custom_range_partition(p.release());
}
ASSERT_OK(table_creator->Create());
- NO_FATALS(CheckTabletCount(kTableName, 13));
+ NO_FATALS(CheckTabletCount(kTableName, 12));
// Make sure it's possible to insert rows into the table for all the existing
// the paritions: first check the range of table-wide schema, then check
@@ -395,10 +430,8 @@ TEST_F(FlexPartitioningCreateTableTest,
DefaultAndCustomHashBuckets) {
// TODO(aserbin): uncomment CheckTableRowsNum() once partition pruning works
ASSERT_OK(InsertTestRows(kTableName, -111, 0));
NO_FATALS(CheckLiveRowCount(kTableName, 111));
- //NO_FATALS(CheckTableRowsNum(kTableName, 222));
ASSERT_OK(InsertTestRows(kTableName, 111, 555));
NO_FATALS(CheckLiveRowCount(kTableName, 555));
- //NO_FATALS(CheckTableRowsNum(kTableName, 555));
// Meanwhile, inserting into non-covered ranges should result in a proper
// error status return to the client attempting such an operation.
diff --git a/src/kudu/client/table_creator-internal.cc
b/src/kudu/client/table_creator-internal.cc
index 3d64b27..85757af 100644
--- a/src/kudu/client/table_creator-internal.cc
+++ b/src/kudu/client/table_creator-internal.cc
@@ -40,7 +40,8 @@ KuduTableCreator::KuduRangePartition::Data::Data(
: lower_bound_type_(lower_bound_type),
upper_bound_type_(upper_bound_type),
lower_bound_(lower_bound),
- upper_bound_(upper_bound) {
+ upper_bound_(upper_bound),
+ is_table_wide_hash_schema_(false) {
}
Status KuduTableCreator::KuduRangePartition::Data::add_hash_partitions(
diff --git a/src/kudu/client/table_creator-internal.h
b/src/kudu/client/table_creator-internal.h
index 23a5c25..590e105 100644
--- a/src/kudu/client/table_creator-internal.h
+++ b/src/kudu/client/table_creator-internal.h
@@ -110,6 +110,7 @@ class KuduTableCreator::KuduRangePartition::Data {
std::unique_ptr<KuduPartialRow> upper_bound_;
HashSchema hash_schema_;
+ bool is_table_wide_hash_schema_;
private:
DISALLOW_COPY_AND_ASSIGN(Data);
diff --git a/src/kudu/common/partition-test.cc
b/src/kudu/common/partition-test.cc
index abe779e..41ddaa9 100644
--- a/src/kudu/common/partition-test.cc
+++ b/src/kudu/common/partition-test.cc
@@ -923,9 +923,10 @@ TEST_F(PartitionTest, TestVaryingHashSchemasPerRange) {
ASSERT_OK(upper.SetStringCopy("a", "a4"));
ASSERT_OK(upper.SetStringCopy("b", "b4"));
bounds.emplace_back(lower, upper);
- range_hash_schemas.emplace_back(PartitionSchema::HashSchema());
+ range_hash_schemas.emplace_back(partition_schema.hash_schema());
+ // Use the table-wide hash schema for this range.
bounds_with_hash_schemas.emplace_back(make_pair(std::move(lower),
std::move(upper)),
- PartitionSchema::HashSchema());
+ partition_schema.hash_schema());
}
{ // [(a5, b5, _), (a6, _, c6))
@@ -1283,7 +1284,7 @@ TEST_F(PartitionTest,
TestVaryingHashSchemasPerUnboundedRanges) {
vector<Partition> partitions;
ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas,
schema, &partitions));
- ASSERT_EQ(12, partitions.size());
+ ASSERT_EQ(11, partitions.size());
// Partitions below sorted by range, can verify that the partition keyspace
is filled by checking
// that the start key of the first partition and the end key of the last
partition is cleared.
@@ -1315,67 +1316,55 @@ TEST_F(PartitionTest,
TestVaryingHashSchemasPerUnboundedRanges) {
EXPECT_EQ(string("\0\0\0\3", 4), partitions[3].partition_key_start());
EXPECT_EQ(string("\0\0\0\3" "a1\0\0\0\0c1", 12),
partitions[3].partition_key_end());
- ASSERT_EQ(1, partitions[4].hash_buckets().size());
- EXPECT_EQ(0, partitions[4].hash_buckets()[0]);
- EXPECT_EQ(string("a2\0\0b2\0\0", 8), partitions[4].range_key_start());
- EXPECT_EQ(string("a3\0\0b3\0\0", 8), partitions[4].range_key_end());
- EXPECT_EQ(string("\0\0\0\0" "a2\0\0b2\0\0", 12),
partitions[4].partition_key_start());
- EXPECT_EQ(string("\0\0\0\0" "a3\0\0b3\0\0", 12),
partitions[4].partition_key_end());
+ ASSERT_EQ(0, partitions[4].hash_buckets().size());
- ASSERT_EQ(1, partitions[5].hash_buckets().size());
- EXPECT_EQ(1, partitions[5].hash_buckets()[0]);
- EXPECT_EQ(string("a2\0\0b2\0\0", 8), partitions[5].range_key_start());
- EXPECT_EQ(string("a3\0\0b3\0\0", 8), partitions[5].range_key_end());
- EXPECT_EQ(string("\0\0\0\1" "a2\0\0b2\0\0", 12),
partitions[5].partition_key_start());
- EXPECT_EQ(string("\0\0\0\1" "a3\0\0b3\0\0", 12),
partitions[5].partition_key_end());
+ ASSERT_EQ(2, partitions[5].hash_buckets().size());
+ EXPECT_EQ(0, partitions[5].hash_buckets()[0]);
+ EXPECT_EQ(0, partitions[5].hash_buckets()[1]);
+ EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[5].range_key_start());
+ EXPECT_EQ("", partitions[5].range_key_end());
+ EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a4\0\0b4\0\0", 16),
partitions[5].partition_key_start());
+ EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1", 8),
partitions[5].partition_key_end());
ASSERT_EQ(2, partitions[6].hash_buckets().size());
EXPECT_EQ(0, partitions[6].hash_buckets()[0]);
- EXPECT_EQ(0, partitions[6].hash_buckets()[1]);
+ EXPECT_EQ(1, partitions[6].hash_buckets()[1]);
EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[6].range_key_start());
EXPECT_EQ("", partitions[6].range_key_end());
- EXPECT_EQ(string("\0\0\0\0" "\0\0\0\0" "a4\0\0b4\0\0", 16),
partitions[6].partition_key_start());
- EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1", 8),
partitions[6].partition_key_end());
+ EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a4\0\0b4\0\0",
16),partitions[6].partition_key_start());
+ EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2", 8),
partitions[6].partition_key_end());
ASSERT_EQ(2, partitions[7].hash_buckets().size());
EXPECT_EQ(0, partitions[7].hash_buckets()[0]);
- EXPECT_EQ(1, partitions[7].hash_buckets()[1]);
+ EXPECT_EQ(2, partitions[7].hash_buckets()[1]);
EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[7].range_key_start());
EXPECT_EQ("", partitions[7].range_key_end());
- EXPECT_EQ(string("\0\0\0\0" "\0\0\0\1" "a4\0\0b4\0\0",
16),partitions[7].partition_key_start());
- EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2", 8),
partitions[7].partition_key_end());
+ EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2" "a4\0\0b4\0\0", 16),
partitions[7].partition_key_start());
+ EXPECT_EQ(string("\0\0\0\1", 4), partitions[7].partition_key_end());
ASSERT_EQ(2, partitions[8].hash_buckets().size());
- EXPECT_EQ(0, partitions[8].hash_buckets()[0]);
- EXPECT_EQ(2, partitions[8].hash_buckets()[1]);
+ EXPECT_EQ(1, partitions[8].hash_buckets()[0]);
+ EXPECT_EQ(0, partitions[8].hash_buckets()[1]);
EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[8].range_key_start());
EXPECT_EQ("", partitions[8].range_key_end());
- EXPECT_EQ(string("\0\0\0\0" "\0\0\0\2" "a4\0\0b4\0\0", 16),
partitions[8].partition_key_start());
- EXPECT_EQ(string("\0\0\0\1", 4), partitions[8].partition_key_end());
+ EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a4\0\0b4\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());
ASSERT_EQ(2, partitions[9].hash_buckets().size());
EXPECT_EQ(1, partitions[9].hash_buckets()[0]);
- EXPECT_EQ(0, partitions[9].hash_buckets()[1]);
+ EXPECT_EQ(1, partitions[9].hash_buckets()[1]);
EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[9].range_key_start());
EXPECT_EQ("", partitions[9].range_key_end());
- EXPECT_EQ(string("\0\0\0\1" "\0\0\0\0" "a4\0\0b4\0\0", 16),
partitions[9].partition_key_start());
- EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1", 8),
partitions[9].partition_key_end());
+ EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a4\0\0b4\0\0",
16),partitions[9].partition_key_start());
+ EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2", 8),
partitions[9].partition_key_end());
ASSERT_EQ(2, partitions[10].hash_buckets().size());
EXPECT_EQ(1, partitions[10].hash_buckets()[0]);
- EXPECT_EQ(1, partitions[10].hash_buckets()[1]);
+ EXPECT_EQ(2, partitions[10].hash_buckets()[1]);
EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[10].range_key_start());
EXPECT_EQ("", partitions[10].range_key_end());
- EXPECT_EQ(string("\0\0\0\1" "\0\0\0\1" "a4\0\0b4\0\0",
16),partitions[10].partition_key_start());
- EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2", 8),
partitions[10].partition_key_end());
-
- ASSERT_EQ(2, partitions[10].hash_buckets().size());
- EXPECT_EQ(1, partitions[11].hash_buckets()[0]);
- EXPECT_EQ(2, partitions[11].hash_buckets()[1]);
- EXPECT_EQ(string("a4\0\0b4\0\0", 8), partitions[11].range_key_start());
- EXPECT_EQ("", partitions[11].range_key_end());
- EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2" "a4\0\0b4\0\0", 16),
partitions[11].partition_key_start());
- EXPECT_EQ("", partitions[11].partition_key_end());
+ EXPECT_EQ(string("\0\0\0\1" "\0\0\0\2" "a4\0\0b4\0\0", 16),
partitions[10].partition_key_start());
+ EXPECT_EQ("", partitions[10].partition_key_end());
}
TEST_F(PartitionTest, TestPartitionSchemaPB) {
diff --git a/src/kudu/common/partition.cc b/src/kudu/common/partition.cc
index c01fbcf..1925b87 100644
--- a/src/kudu/common/partition.cc
+++ b/src/kudu/common/partition.cc
@@ -555,11 +555,6 @@ Status PartitionSchema::CreatePartitions(
RETURN_NOT_OK(EncodeRangeSplits(split_rows, schema, &splits));
RETURN_NOT_OK(SplitRangeBounds(schema, splits, &bounds_with_hash_schemas));
- // Maps each partition to its respective hash schemas within
'bounds_with_hash_schemas',
- // needed for logic later in function for filling in holes in partition key
space. Will be
- // empty if no per range hash schemas are used.
- vector<int> partition_idx_to_hash_schema_idx;
-
// Even if no hash partitioning for a table is specified, there must be at
// least one element in 'base_hash_partitions': it's used to build the result
// set of range partitions.
@@ -568,6 +563,12 @@ Status PartitionSchema::CreatePartitions(
DCHECK(base_hash_partitions.size() > 1 ||
base_hash_partitions.front().hash_buckets().empty());
+ // Maps each partition to its respective hash schema within
+ // 'bounds_with_hash_schemas', needed for the logic later in this method
+ // for filling in holes in partition key space. The container is empty if no
+ // per-range hash schemas are present.
+ vector<size_t> partition_idx_to_hash_schema_idx;
+
if (range_hash_schemas.empty()) {
// Create a partition per range bound and hash bucket combination.
vector<Partition> new_partitions;
@@ -587,23 +588,15 @@ Status PartitionSchema::CreatePartitions(
DCHECK(split_rows.empty());
vector<Partition> result_partitions;
// Iterate through each bound and its hash schemas to generate hash
partitions.
- for (int i = 0; i < bounds_with_hash_schemas.size(); ++i) {
+ for (size_t i = 0; i < bounds_with_hash_schemas.size(); ++i) {
const auto& bound = bounds_with_hash_schemas[i];
- const auto& current_range_hash_schema = bound.hash_schema;
- // If current bound's HashSchema is empty, implies use of default
- // table-wide schema. If not empty, generate hash partitions for all the
- // provided hash schemas in this range.
- vector<Partition> current_bound_hash_partitions =
- current_range_hash_schema.empty() ? base_hash_partitions
- : GenerateHashPartitions(
- current_range_hash_schema,
- hash_encoder);
+ vector<Partition> current_bound_hash_partitions = GenerateHashPartitions(
+ bound.hash_schema, hash_encoder);
// Add range information to the partition key.
for (Partition& partition : current_bound_hash_partitions) {
partition.partition_key_start_.append(bound.lower);
partition.partition_key_end_.append(bound.upper);
- int index = current_range_hash_schema.empty() ? -1 : i;
- partition_idx_to_hash_schema_idx.emplace_back(index);
+ partition_idx_to_hash_schema_idx.emplace_back(i);
}
result_partitions.insert(result_partitions.end(),
std::make_move_iterator(current_bound_hash_partitions.begin()),
@@ -630,13 +623,13 @@ Status PartitionSchema::CreatePartitions(
// the absolute start and end case, these holes are filled by clearing the
// partition key beginning at the hash component. For a concrete example,
// see PartitionTest::TestCreatePartitions.
- const HashDimension* hash_dimension;
- for (int j = 0; j < partitions->size(); j++) {
- Partition& partition = (*partitions)[j];
+ for (size_t partition_idx = 0; partition_idx < partitions->size();
++partition_idx) {
+ Partition& partition = (*partitions)[partition_idx];
+ const int hash_buckets_num =
static_cast<int>(partition.hash_buckets().size());
// Find the first zero-valued bucket from the end and truncate the
partition key
// starting from that bucket onwards for zero-valued buckets.
if (partition.range_key_start().empty()) {
- for (int i = static_cast<int>(partition.hash_buckets().size()) - 1; i >=
0; i--) {
+ for (int i = hash_buckets_num - 1; i >= 0; --i) {
if (partition.hash_buckets()[i] != 0) {
break;
}
@@ -653,16 +646,13 @@ Status PartitionSchema::CreatePartitions(
// [ (1, 0, "a2b2") -> (1, 1, "a2b2") ]
// [ (1, 1, "a2b2") -> (_, _, "a2b2") ]
if (partition.range_key_end().empty()) {
- for (int i = static_cast<int>(partition.hash_buckets().size()) - 1; i >=
0; i--) {
+ const auto& hash_schema = range_hash_schemas.empty()
+ ? hash_schema_
+ :
bounds_with_hash_schemas[partition_idx_to_hash_schema_idx[partition_idx]].hash_schema;
+ for (int i = hash_buckets_num - 1; i >= 0; --i) {
partition.partition_key_end_.erase(kEncodedBucketSize * i);
- int32_t hash_bucket = partition.hash_buckets()[i] + 1;
- if (range_hash_schemas.empty() || partition_idx_to_hash_schema_idx[j]
== -1) {
- hash_dimension = &hash_schema_[i];
- } else {
- const auto& hash_schemas_idx = partition_idx_to_hash_schema_idx[j];
- hash_dimension =
&bounds_with_hash_schemas[hash_schemas_idx].hash_schema[i];
- }
- if (hash_bucket != hash_dimension->num_buckets) {
+ const int32_t hash_bucket = partition.hash_buckets()[i] + 1;
+ if (hash_bucket != hash_schema[i].num_buckets) {
hash_encoder.Encode(&hash_bucket, &partition.partition_key_end_);
break;
}
diff --git a/src/kudu/common/partition_pruner-test.cc
b/src/kudu/common/partition_pruner-test.cc
index 95bb56a..3d7a9e7 100644
--- a/src/kudu/common/partition_pruner-test.cc
+++ b/src/kudu/common/partition_pruner-test.cc
@@ -1111,172 +1111,161 @@ TEST_F(PartitionPrunerTest,
TestHashSchemasPerRangePruning) {
{ ColumnId(0), ColumnId(1), ColumnId(2) },
3);
- PartitionSchema partition_schema;
- auto pb = PartitionSchemaPB();
+ PartitionSchemaPB pb;
CreatePartitionSchemaPB({"C"}, { {{"A"}, 2, 0}, {{"B"}, 2, 0} }, &pb);
vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
vector<PartitionSchema::HashSchema> range_hash_schemas;
- // Need to add per range hash schema components to the field
'range_with_hash_schemas_'
- // of PartitionSchema because PartitionPruner will use them to construct
partition key ranges.
- // Currently, PartitionSchema::CreatePartitions() does not leverage this
field
- // so these components will have to be passed separately to the function as
well.
+ // Need to add per range hash schema components to the field
+ // 'ranges_with_hash_schemas_' of PartitionSchema because PartitionPruner
will
+ // use them to construct partition key ranges. Currently,
+ // PartitionSchema::CreatePartitions() does not leverage this field, so these
+ // components will have to be passed separately to the function as well.
- // [(_, _, a), (_, _, c))
- {
- AddRangePartitionWithSchema(schema, {{"C", "a"}}, {{"C", "c"}}, {}, {},
- { {{"A"}, 3, 0} }, &bounds,
&range_hash_schemas, &pb);
- }
+ // None of the ranges below uses the table-wide hash schema.
+ // [(_, _, a), (_, _, c))
+ AddRangePartitionWithSchema(schema, {{"C", "a"}}, {{"C", "c"}}, {}, {},
+ { {{"A"}, 3, 0} }, &bounds, &range_hash_schemas,
&pb);
// [(_, _, d), (_, _, f))
- {
- AddRangePartitionWithSchema(schema, {{"C", "d"}}, {{"C", "f"}}, {}, {},
- { {{"A"}, 2, 0}, {{"B"}, 3, 0} },
- &bounds, &range_hash_schemas, &pb);
- }
-
+ AddRangePartitionWithSchema(schema, {{"C", "d"}}, {{"C", "f"}}, {}, {},
+ { {{"A"}, 2, 0}, {{"B"}, 3, 0} },
+ &bounds, &range_hash_schemas, &pb);
// [(_, _, h), (_, _, j))
- {
- AddRangePartitionWithSchema(schema, {{"C", "h"}}, {{"C", "j"}}, {}, {},
- {}, &bounds, &range_hash_schemas, &pb);
- }
-
+ AddRangePartitionWithSchema(schema, {{"C", "h"}}, {{"C", "j"}}, {}, {},
+ {}, &bounds, &range_hash_schemas, &pb);
// [(_, _, k), (_, _, m))
- {
- AddRangePartitionWithSchema(schema, {{"C", "k"}}, {{"C", "m"}}, {}, {},
- { {{"B"}, 2, 0} }, &bounds,
&range_hash_schemas, &pb);
-
- }
+ AddRangePartitionWithSchema(schema, {{"C", "k"}}, {{"C", "m"}}, {}, {},
+ { {{"B"}, 2, 0} }, &bounds, &range_hash_schemas,
&pb);
+ PartitionSchema partition_schema;
ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
vector<Partition> partitions;
ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas,
schema, &partitions));
-
- ASSERT_EQ(15, partitions.size());
+ ASSERT_EQ(12, partitions.size());
// Applies the specified predicates to a scan and checks that the expected
// number of partitions are pruned.
const auto check = [&] (const vector<ColumnPredicate>& predicates,
- const string& lower_bound_partition_key,
- const string& upper_bound_partition_key,
- size_t remaining_tablets,
- size_t pruner_ranges) {
+ const string& lower_bound_partition_key,
+ const string& upper_bound_partition_key,
+ size_t remaining_tablets,
+ size_t pruner_ranges) {
ScanSpec spec;
-
spec.SetLowerBoundPartitionKey(lower_bound_partition_key);
spec.SetExclusiveUpperBoundPartitionKey(upper_bound_partition_key);
for (const auto& pred : predicates) {
spec.AddPredicate(pred);
}
-
- NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
- remaining_tablets, pruner_ranges));
+ CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+ remaining_tablets, pruner_ranges);
};
constexpr int8_t zero = 0;
constexpr int8_t one = 1;
- Slice a = "a";
- Slice b = "b";
- Slice e = "e";
- Slice f = "f";
- Slice i = "i";
- Slice l = "l";
- Slice m = "m";
+ const Slice a = "a";
+ const Slice b = "b";
+ const Slice e = "e";
+ const Slice f = "f";
+ const Slice i = "i";
+ const Slice l = "l";
+ const Slice m = "m";
// No Bounds
- check({}, "", "", 15, 15);
+ NO_FATALS(check({}, "", "", 12, 12));
// A = 1
- check({ ColumnPredicate::Equality(schema.column(0), &one)}, "", "", 8, 8);
-
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &one) },
+ "", "", 7, 7));
// B = 1
- check({ ColumnPredicate::Equality(schema.column(1), &one)}, "", "", 8, 8);
-
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one) },
+ "", "", 7, 7));
// A = 0
// B = 1
// C >= "e"
- check({ ColumnPredicate::Equality(schema.column(0), &zero),
- ColumnPredicate::Equality(schema.column(1), &one),
- ColumnPredicate::Range(schema.column(2), &e, nullptr)}, "", "", 3,
3);
-
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &zero),
+ ColumnPredicate::Equality(schema.column(1), &one),
+ ColumnPredicate::Range(schema.column(2), &e, nullptr) },
+ "", "", 3, 3));
// A = 0
// B = 1
// C = "e"
- check({ ColumnPredicate::Equality(schema.column(0), &zero),
- ColumnPredicate::Equality(schema.column(1), &one),
- ColumnPredicate::Equality(schema.column(2), &e)}, "", "", 1, 1);
-
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(0), &zero),
+ ColumnPredicate::Equality(schema.column(1), &one),
+ ColumnPredicate::Equality(schema.column(2), &e) },
+ "", "", 1, 1));
// B = 1
// C >= "b"
// C < "j"
- check({ ColumnPredicate::Equality(schema.column(1), &one),
- ColumnPredicate::Range(schema.column(2), &b, nullptr),
- ColumnPredicate::Range(schema.column(2), nullptr, &i)}, "", "", 7,
7);
-
-
- // A = 0
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one),
+ ColumnPredicate::Range(schema.column(2), &b, nullptr),
+ ColumnPredicate::Range(schema.column(2), nullptr, &i) },
+ "", "", 6, 6));
+ // B = 0
// C >= "e"
// C < "l"
- check({ ColumnPredicate::Equality(schema.column(1), &zero),
- ColumnPredicate::Range(schema.column(2), &e, nullptr),
- ColumnPredicate::Range(schema.column(2), nullptr, &l)}, "", "", 5,
5);
-
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &zero),
+ ColumnPredicate::Range(schema.column(2), &e, nullptr),
+ ColumnPredicate::Range(schema.column(2), nullptr, &l) },
+ "", "", 4, 4));
// C >= "a"
// C < "b"
- check({ ColumnPredicate::Range(schema.column(2), &a, &b)}, "", "", 3, 3);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &b) },
+ "", "", 3, 3));
// C >= "a"
// C < "e"
- check({ ColumnPredicate::Range(schema.column(2), &a, &e)}, "", "", 9, 9);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &e) },
+ "", "", 9, 9));
// C >= "e"
// C < "i"
- check({ ColumnPredicate::Range(schema.column(2), &e, &i)}, "", "", 10, 10);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &e, &i) },
+ "", "", 7, 7));
// C >= "a"
// C < "l"
- check({ ColumnPredicate::Range(schema.column(2), &a, &l)}, "", "", 15, 15);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &a, &l) },
+ "", "", 12, 12));
// C >= "i"
// C < "l"
- check({ ColumnPredicate::Range(schema.column(2), &i, &l)}, "", "", 6, 6);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &i, &l) },
+ "", "", 3, 3));
// C >= "e"
- check({ ColumnPredicate::Range(schema.column(2), &e, nullptr)}, "", "", 12,
12);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &e, nullptr) },
+ "", "", 9, 9));
// C < "f"
- check({ ColumnPredicate::Range(schema.column(2), nullptr, &f)}, "", "", 9,
9);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), nullptr, &f) },
+ "", "", 9, 9));
// C >= "f"
- check({ ColumnPredicate::Range(schema.column(2), &f, nullptr)}, "", "", 6,
6);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &f, nullptr) },
+ "", "", 3, 3));
// C < "a"
- check({ ColumnPredicate::Range(schema.column(2), nullptr, &a)}, "", "", 0,
0);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), nullptr, &a) },
+ "", "", 0, 0));
// C >= "m"
- check({ ColumnPredicate::Range(schema.column(2), &m, nullptr)}, "", "", 0,
0);
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(2), &m, nullptr) },
+ "", "", 0, 0));
// Uses None predicate to short circuit scan
- check({ ColumnPredicate::None(schema.column(2))}, "", "", 0, 0);
+ NO_FATALS(check({ ColumnPredicate::None(schema.column(2))}, "", "", 0, 0));
// partition key >= (hash=1, hash=0)
- check({}, string("\0\0\0\1\0\0\0\0", 8), "", 8, 8);
+ NO_FATALS(check({}, string("\0\0\0\1\0\0\0\0", 8), "", 7, 7));
// partition key < (hash=1, hash=0)
- check({}, "", string("\0\0\0\1\0\0\0\0", 8), 7, 7);
+ NO_FATALS(check({}, "", string("\0\0\0\1\0\0\0\0", 8), 5, 5));
// C >= "e"
// C < "m"
// partition key >= (hash=1)
- check({ColumnPredicate::Range(schema.column(2), &e, &m)}, string("\0\0\0\1",
4), "", 6, 6);
-
+ NO_FATALS(check({ColumnPredicate::Range(schema.column(2), &e, &m)},
+ string("\0\0\0\1", 4), "", 5, 5));
// C >= "e"
// C < "m"
// partition key < (hash=1)
- check({ColumnPredicate::Range(schema.column(2), &e, &m)}, "",
string("\0\0\0\1", 4), 6, 6);
+ NO_FATALS(check({ColumnPredicate::Range(schema.column(2), &e, &m)}, "",
+ string("\0\0\0\1", 4), 4, 4));
}
TEST_F(PartitionPrunerTest,
TestHashSchemasPerRangeWithPartialPrimaryKeyRangePruning) {
@@ -1407,37 +1396,32 @@ TEST_F(PartitionPrunerTest,
TestInListHashPruningPerRange) {
{ ColumnId(0), ColumnId(1), ColumnId(2) },
3);
- PartitionSchema partition_schema;
- auto pb = PartitionSchemaPB();
+ PartitionSchemaPB pb;
CreatePartitionSchemaPB({"A"}, { {{"B", "C"}, 3, 0} }, &pb);
vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
vector<PartitionSchema::HashSchema> range_hash_schemas;
- // [(a, _, _), (c, _, _))
- {
- AddRangePartitionWithSchema(schema, {{"A", "a"}}, {{"A", "c"}}, {}, {},
- { {{"B"}, 3, 0} }, &bounds,
&range_hash_schemas, &pb);
- }
+ // None of the ranges below uses the table-wide hash schema.
+ // [(a, _, _), (c, _, _))
+ AddRangePartitionWithSchema(schema, {{"A", "a"}}, {{"A", "c"}}, {}, {},
+ { {{"B"}, 3, 0} }, &bounds, &range_hash_schemas,
&pb);
// [(c, _, _), (e, _, _))
- {
- AddRangePartitionWithSchema(schema, {{"A", "c"}}, {{"A", "e"}}, {}, {},
- {}, &bounds, &range_hash_schemas, &pb);
- }
-
+ AddRangePartitionWithSchema(schema, {{"A", "c"}}, {{"A", "e"}}, {}, {},
+ {}, &bounds, &range_hash_schemas, &pb);
// [(e, _, _), (g, _, _))
- {
- AddRangePartitionWithSchema(schema, {{"A", "e"}}, {{"A", "g"}}, {}, {},
- { {{"C"}, 3, 0} }, &bounds,
&range_hash_schemas, &pb);
- }
+ AddRangePartitionWithSchema(schema, {{"A", "e"}}, {{"A", "g"}}, {}, {},
+ { {{"C"}, 3, 0} }, &bounds, &range_hash_schemas,
&pb);
+ PartitionSchema partition_schema;
ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
vector<Partition> partitions;
- ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas,
schema, &partitions));
+ ASSERT_OK(partition_schema.CreatePartitions(
+ {}, bounds, range_hash_schemas, schema, &partitions));
- ASSERT_EQ(9, partitions.size());
+ ASSERT_EQ(7, partitions.size());
// Applies the specified predicates to a scan and checks that the expected
// number of partitions are pruned.
@@ -1445,13 +1429,11 @@ TEST_F(PartitionPrunerTest,
TestInListHashPruningPerRange) {
size_t remaining_tablets,
size_t pruner_ranges) {
ScanSpec spec;
-
for (const auto& pred : predicates) {
spec.AddPredicate(pred);
}
-
- NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
- remaining_tablets, pruner_ranges));
+ CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+ remaining_tablets, pruner_ranges);
};
// zero, one, eight are in different buckets when bucket number is 3 and
seed is 0.
@@ -1464,15 +1446,18 @@ TEST_F(PartitionPrunerTest,
TestInListHashPruningPerRange) {
// B in [0, 1, 8];
B_values = { &zero, &one, &eight };
- check({ ColumnPredicate::InList(schema.column(1), &B_values) }, 9, 9);
+ NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values) },
+ 7, 7));
// B in [0, 1];
B_values = { &zero, &one };
- check({ ColumnPredicate::InList(schema.column(1), &B_values) }, 8, 8);
+ NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values) },
+ 6, 6));
// C in [0, 1];
C_values = { &zero, &one };
- check({ ColumnPredicate::InList(schema.column(2), &C_values) }, 8, 8);
+ NO_FATALS(check({ ColumnPredicate::InList(schema.column(2), &C_values) },
+ 6, 6));
// B in [0, 1], C in [0, 1]
// (0, 0) in bucket 2
@@ -1481,65 +1466,56 @@ TEST_F(PartitionPrunerTest,
TestInListHashPruningPerRange) {
// (1, 1) in bucket 0
B_values = { &zero, &one };
C_values = { &zero, &one };
- check({ ColumnPredicate::InList(schema.column(1), &B_values),
- ColumnPredicate::InList(schema.column(2), &C_values) },
- 7, 7);
+ NO_FATALS(check({ ColumnPredicate::InList(schema.column(1), &B_values),
+ ColumnPredicate::InList(schema.column(2), &C_values) },
+ 5, 5));
// B = 0, C in [0, 1]
C_values = { &zero, &one };
- check({ ColumnPredicate::Equality(schema.column(1), &zero),
- ColumnPredicate::InList(schema.column(2), &C_values) },
- 4, 4);
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &zero),
+ ColumnPredicate::InList(schema.column(2), &C_values) },
+ 4, 4));
// B = 1, C in [0, 1]
C_values = { &zero, &one };
- check({ ColumnPredicate::Equality(schema.column(1), &one),
- ColumnPredicate::InList(schema.column(2), &C_values) },
- 5, 5);
+ NO_FATALS(check({ ColumnPredicate::Equality(schema.column(1), &one),
+ ColumnPredicate::InList(schema.column(2), &C_values) },
+ 4, 4));
}
TEST_F(PartitionPrunerTest, TestSingleRangeElementAndBoundaryCase) {
// CREATE TABLE t
// (A INT8, B STRING)
// PRIMARY KEY (A, B)
- // PARTITION BY RANGE (A)
- // DISTRIBUTE BY HASH(B) INTO 2 BUCKETS;
+ // PARTITION BY RANGE (A);
Schema schema({ ColumnSchema("A", INT8),
ColumnSchema("B", STRING) },
{ ColumnId(0), ColumnId(1) },
2);
- PartitionSchema partition_schema;
- auto pb = PartitionSchemaPB();
- CreatePartitionSchemaPB({"A"}, { {{"B"}, 2, 0} }, &pb);
+ PartitionSchemaPB pb;
+ CreatePartitionSchemaPB({"A"}, {}, &pb);
vector<pair<KuduPartialRow, KuduPartialRow>> bounds;
vector<PartitionSchema::HashSchema> range_hash_schemas;
// [(0, _), (1, _))
- {
- AddRangePartitionWithSchema(schema, {}, {}, {{"A", 0}}, {{"A", 1}},
- {{{"B"}, 4, 0}}, &bounds, &range_hash_schemas,
&pb);
- }
-
+ AddRangePartitionWithSchema(schema, {}, {}, {{"A", 0}}, {{"A", 1}},
+ {{{"B"}, 4, 0}}, &bounds, &range_hash_schemas,
&pb);
// [(1, _), (2, _))
- {
- AddRangePartitionWithSchema(schema, {}, {}, {{"A", 1}}, {{"A", 2}},
- {}, &bounds, &range_hash_schemas, &pb);
- }
-
+ AddRangePartitionWithSchema(schema, {}, {}, {{"A", 1}}, {{"A", 2}},
+ {}, &bounds, &range_hash_schemas, &pb);
// [(2, _), (3, _))
- {
- AddRangePartitionWithSchema(schema, {}, {}, {{"A", 2}}, {{"A", 3}},
- { {{"B"}, 3, 0} }, &bounds,
&range_hash_schemas, &pb);
- }
+ AddRangePartitionWithSchema(schema, {}, {}, {{"A", 2}}, {{"A", 3}},
+ { {{"B"}, 3, 0} }, &bounds, &range_hash_schemas,
&pb);
+ PartitionSchema partition_schema;
ASSERT_OK(PartitionSchema::FromPB(pb, schema, &partition_schema));
vector<Partition> partitions;
ASSERT_OK(partition_schema.CreatePartitions({}, bounds, range_hash_schemas,
schema, &partitions));
- ASSERT_EQ(9, partitions.size());
+ ASSERT_EQ(8, partitions.size());
// Applies the specified predicates to a scan and checks that the expected
// number of partitions are pruned.
@@ -1547,13 +1523,11 @@ TEST_F(PartitionPrunerTest,
TestSingleRangeElementAndBoundaryCase) {
size_t remaining_tablets,
size_t pruner_ranges) {
ScanSpec spec;
-
for (const auto& pred : predicates) {
spec.AddPredicate(pred);
}
-
- NO_FATALS(CheckPrunedPartitions(schema, partition_schema, partitions, spec,
- remaining_tablets, pruner_ranges));
+ CheckPrunedPartitions(schema, partition_schema, partitions, spec,
+ remaining_tablets, pruner_ranges);
};
constexpr int8_t zero = 0;
@@ -1562,39 +1536,41 @@ TEST_F(PartitionPrunerTest,
TestSingleRangeElementAndBoundaryCase) {
constexpr int8_t three = 3;
// No Bounds
- check({}, 9, 9);
+ NO_FATALS(check({}, 8, 8));
// A >= 0
- check({ ColumnPredicate::Range(schema.column(0), &zero, nullptr)}, 9, 9);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &zero, nullptr) },
+ 8, 8));
// A >= 1
- check({ ColumnPredicate::Range(schema.column(0), &one, nullptr)}, 5, 5);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, nullptr) },
+ 4, 4));
// A < 1
- check({ ColumnPredicate::Range(schema.column(0), nullptr, &one)}, 4, 4);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &one) },
+ 4, 4));
// A >= 2
- check({ ColumnPredicate::Range(schema.column(0), &two, nullptr)}, 3, 3);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &two, nullptr) },
+ 3, 3));
// A < 2
- check({ ColumnPredicate::Range(schema.column(0), nullptr, &two)}, 6, 6);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &two) },
+ 5, 5));
// A < 3
- check({ ColumnPredicate::Range(schema.column(0), nullptr, &three)}, 9, 9);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), nullptr, &three)
},
+ 8, 8));
// A >= 0
// A < 2
- check({ ColumnPredicate::Range(schema.column(0), &zero, &two)}, 6, 6);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &zero, &two) },
+ 5, 5));
// A >= 1
// A < 2
- check({ ColumnPredicate::Range(schema.column(0), &one, &two)}, 2, 2);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, &two) },
+ 1, 1));
// A >= 1
// A < 3
- check({ ColumnPredicate::Range(schema.column(0), &one, &three)}, 5, 5);
-
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &one, &three) },
+ 4, 4));
// A >= 3
- check({ ColumnPredicate::Range(schema.column(0), &three, nullptr)}, 0, 0);
+ NO_FATALS(check({ ColumnPredicate::Range(schema.column(0), &three, nullptr)
},
+ 0, 0));
}
+
} // namespace kudu
diff --git a/src/kudu/common/partition_pruner.cc
b/src/kudu/common/partition_pruner.cc
index 6549001..7a7e82f 100644
--- a/src/kudu/common/partition_pruner.cc
+++ b/src/kudu/common/partition_pruner.cc
@@ -440,8 +440,7 @@ void PartitionPruner::Init(const Schema& schema,
vector<RangeBounds> range_bounds;
vector<PartitionSchema::HashSchema> hash_schemas_per_range;
for (const auto& range : partition_schema.ranges_with_hash_schemas_) {
- const auto& hash_schema = range.hash_schema.empty() ?
- partition_schema.hash_schema_ : range.hash_schema;
+ const auto& hash_schema = range.hash_schema;
// Both lower and upper bounds are unbounded.
if (scan_range_lower_bound.empty() && scan_range_upper_bound.empty()) {
range_bounds.emplace_back(RangeBounds{range.lower, range.upper});
diff --git a/src/kudu/integration-tests/table_locations-itest.cc
b/src/kudu/integration-tests/table_locations-itest.cc
index f1cafb9..5fe8ecd 100644
--- a/src/kudu/integration-tests/table_locations-itest.cc
+++ b/src/kudu/integration-tests/table_locations-itest.cc
@@ -487,9 +487,10 @@ TEST_F(TableLocationsTest, TestRangeSpecificHashing) {
HashSchema hash_schema_6 = { { { "key" }, 6, 2 } };
range_hash_schemas.emplace_back(hash_schema_6);
- // Table-wide hash schema, applied to range by default if no per-range
schema is specified.
+ // Use 5 bucket hash schema as the table-wide one.
HashSchema table_hash_schema_5 = { { { "val" }, 5, 4 } };
- range_hash_schemas.emplace_back();
+ // Apply table-wide hash schema applied to this range.
+ range_hash_schemas.emplace_back(table_hash_schema_5);
ASSERT_OK(CreateTable(
table_name, schema, {}, bounds, range_hash_schemas,
table_hash_schema_5));