blob: 97a90927b20764a710cb37e4e7237512e6745ba1 [file] [log] [blame]
/**
* 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 <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <memory>
#include <utility>
#include <vector>
#include "catalog/CatalogTypedefs.hpp"
#include "catalog/PartitionScheme.hpp"
#include "catalog/PartitionSchemeHeader.hpp"
#include "storage/StorageBlockInfo.hpp"
#include "types/TypeFactory.hpp"
#include "types/TypeID.hpp"
#include "types/TypedValue.hpp"
#include "types/operations/comparisons/Comparison.hpp"
#include "types/operations/comparisons/EqualComparison.hpp"
#include "gtest/gtest.h"
using std::move;
using std::size_t;
namespace quickstep {
class Type;
TEST(PartitionSchemeHeaderTest, IntegerHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 4;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const int kSampleInts[] = {
0, 1, 2, 3, 400, 501, 64783970, 78437883, -2784627};
const size_t num_ints = sizeof(kSampleInts) / sizeof(kSampleInts[0]);
for (size_t i = 0; i < num_ints; ++i) {
// Check if the partition id returned by the partition scheme for
// an integer is the same as the hash of the integer modulus the number
// of partitions.
EXPECT_EQ(TypedValue(kSampleInts[i]).getHash() % num_partitions,
partition_scheme_header->getPartitionId(TypedValue(kSampleInts[i])));
}
}
TEST(PartitionSchemeHeaderTest, LongHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 8;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const std::int64_t kSampleLongs[] = {INT64_C(10),
INT64_C(100),
INT64_C(1025),
INT64_C(9876543),
INT64_C(-89234758937573987)};
const size_t num_longs = sizeof(kSampleLongs) / sizeof(kSampleLongs[0]);
// Check if the partition id returned by the partition scheme for
// a long is the same as the hash of the long number modulus the number
// of partitions.
for (size_t i = 0; i < num_longs; ++i) {
EXPECT_EQ(TypedValue(kSampleLongs[i]).getHash() % num_partitions,
partition_scheme_header->getPartitionId(TypedValue(kSampleLongs[i])));
}
}
TEST(PartitionSchemeHeaderTest, FloatHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 5;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const float kSampleFloats[] = {
285728.895680f, 924005.4989f, -8973494.37438f};
const size_t num_floats = sizeof(kSampleFloats) / sizeof(kSampleFloats[0]);
// Check if the partition id returned by the partition scheme for
// a float is the same as the hash of the floating point number modulus
// the number of partitions.
for (size_t i = 0; i < num_floats; ++i) {
EXPECT_EQ(TypedValue(kSampleFloats[i]).getHash() % num_partitions,
partition_scheme_header->getPartitionId(TypedValue(kSampleFloats[i])));
}
}
TEST(PartitionSchemeHeaderTest, DoubleHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 6;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const double kSampleDoubles[] = {
1.0378, 763624.46343453, -87238497384.3187431894713};
const size_t num_doubles = sizeof(kSampleDoubles) / sizeof(kSampleDoubles[0]);
// Check if the partition id returned by the partition scheme for
// a double is the same as the hash of the double modulus the number
// of partitions.
for (size_t i = 0; i < num_doubles; ++i) {
EXPECT_EQ(
TypedValue(kSampleDoubles[i]).getHash() % num_partitions,
partition_scheme_header->getPartitionId(TypedValue(kSampleDoubles[i])));
}
}
TEST(PartitionSchemeHeaderTest, CharacterHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 7;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const char *kSampleStrings[] = {
"a", "gerald", "ram", "3081289", "=42?", "+-/*&^%", "hello_world"};
const size_t num_strings = sizeof(kSampleStrings) / sizeof(kSampleStrings[0]);
// Check if the partition id returned by the partition scheme for
// characters is the same as the hash of the characters modulus the number
// of partitions.
for (size_t i = 0; i < num_strings; ++i) {
EXPECT_EQ(
TypedValue(
kChar, kSampleStrings[i], std::strlen(kSampleStrings[i]) + 1)
.getHash() %
num_partitions,
partition_scheme_header->getPartitionId(TypedValue(
kChar, kSampleStrings[i], std::strlen(kSampleStrings[i]) + 1)));
}
}
TEST(PartitionSchemeHeaderTest, VarCharHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 7;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, 0));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const char *kSampleStrings[] = {
"hello", "world", "1234567", "!@#$^&*", "pa345+="};
const size_t num_strings = sizeof(kSampleStrings) / sizeof(kSampleStrings[0]);
// Check if the partition id returned by the partition scheme for
// a variable length string is the same as the hash of the variable length string
// modulus the number of partitions.
for (size_t i = 0; i < num_strings; ++i) {
EXPECT_EQ(
TypedValue(
kVarChar, kSampleStrings[i], std::strlen(kSampleStrings[i]) + 1)
.getHash() %
num_partitions,
partition_scheme_header->getPartitionId(
TypedValue(kVarChar,
kSampleStrings[i],
std::strlen(kSampleStrings[i]) + 1)));
}
}
TEST(PartitionSchemeHeaderTest, IntegerRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are 0, 10, 20.
// Last partition can hold upto infinity.
// First partition can hold from -infinity to -1.
for (int i = 0; i < 3; ++i) {
partition_range.push_back(TypedValue(i * 10));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kInt), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
// Check if the partition id returned by the Range Partition Scheme for
// integers is the same as the partition id into which it is supposed to
// be based on the partition boundaries that we have defined.
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(0)));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(10)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(20)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(30)));
EXPECT_EQ(0u, partition_scheme_header->getPartitionId(TypedValue(-4)));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(15)));
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(6)));
EXPECT_EQ(0u, partition_scheme_header->getPartitionId(TypedValue(-70)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(1000)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(20000)));
}
TEST(PartitionSchemeHeaderTest, LongRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are 0, 10000, 20000, 30000
for (int i = 0; i < 3; ++i) {
partition_range.push_back(TypedValue(i * INT64_C(10000)));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kLong), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
// Check if the partition id returned by the Range Partition Scheme for
// long numbers is the same as the partition id into which it is supposed to
// be based on the partition boundaries that we have defined.
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(0))));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(13456))));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(20000))));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(300123))));
EXPECT_EQ(0u,
partition_scheme_header->getPartitionId(TypedValue(INT64_C(-400000))));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(15123))));
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(INT64_C(6012))));
EXPECT_EQ(0u,
partition_scheme_header->getPartitionId(TypedValue(INT64_C(-7000000))));
}
TEST(PartitionSchemeHeaderTest, FloatRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are 0.0, 10.0, 20.0
for (int i = 0; i < 3; ++i) {
partition_range.push_back(TypedValue(i * 10.0f));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kFloat), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
// Check if the partition id returned by the Range Partition Scheme for
// floats is the same as the partition id into which it is supposed to
// be based on the partition boundaries that we have defined.
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(0.1f)));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(10.00000000f)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(20.23f)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(30.56f)));
EXPECT_EQ(0u, partition_scheme_header->getPartitionId(TypedValue(-4.5f)));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId(TypedValue(15.034f)));
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(6.987f)));
EXPECT_EQ(0u, partition_scheme_header->getPartitionId(TypedValue(-70.384f)));
}
TEST(PartitionSchemeHeaderTest, DoubleRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are 0.00000, 10.00000, 20.00000
for (int i = 0; i < 3; ++i) {
partition_range.push_back(TypedValue(i * 10.00000));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kDouble), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
// Check if the partition id returned by the Range Partition Scheme for
// doubles is the same as the partition id into which it is supposed to
// be based on the partition boundaries that we have defined.
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(0.1897438974)));
EXPECT_EQ(2u,
partition_scheme_header->getPartitionId(TypedValue(10.00000000287489)));
EXPECT_EQ(3u,
partition_scheme_header->getPartitionId(TypedValue(20.23249859403750)));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId(TypedValue(30.567866347563)));
EXPECT_EQ(0u,
partition_scheme_header->getPartitionId(TypedValue(-4.57583978935689)));
EXPECT_EQ(2u,
partition_scheme_header->getPartitionId(TypedValue(15.034248758978936)));
EXPECT_EQ(1u, partition_scheme_header->getPartitionId(TypedValue(6.98792489)));
EXPECT_EQ(
0u, partition_scheme_header->getPartitionId(TypedValue(-70.38454985893768738)));
}
TEST(PartitionSchemeHeaderTest, CharacterRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are the following 3 characters.
const char *kRangeBoundaryStrings[] = {"don", "hippo", "pattasu"};
const size_t num_boundaries = sizeof(kRangeBoundaryStrings) / sizeof(kRangeBoundaryStrings[0]);
for (size_t i = 0; i < num_boundaries; ++i) {
partition_range.push_back(
TypedValue(kChar,
kRangeBoundaryStrings[i],
std::strlen(kRangeBoundaryStrings[i]) + 1));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kChar, 20, false), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const char *kSampleStrings[] = {"amma",
"ganesh",
"e",
"imo",
"master",
"pathetic",
"turing",
"wentao",
"dog",
"zebra"};
const partition_id kExpectedPartitions[] = {0, 1, 1, 2, 2, 2, 3, 3, 0, 3};
const size_t num_strings = sizeof(kExpectedPartitions) / sizeof(kExpectedPartitions[0]);
// Check if the partition id returned by the Range Partition Scheme for
// characters is the same as the partition id into which it is supposed to
// be based on the partition boundaries that we have defined.
for (size_t i = 0; i < num_strings; ++i) {
EXPECT_EQ(
kExpectedPartitions[i],
partition_scheme_header->getPartitionId(TypedValue(
kChar, kSampleStrings[i], std::strlen(kSampleStrings[i]) + 1)));
}
}
TEST(PartitionSchemeHeaderTest, VarCharRangePartitionSchemeHeaderTest) {
std::vector<TypedValue> partition_range;
// Partition boundaries are the following 3 strings.
const char *kRangeBoundaryStrings[] = { "elephant", "jamaica", "zorgonz"};
const size_t num_boundaries = sizeof(kRangeBoundaryStrings) / sizeof(kRangeBoundaryStrings[0]);
for (size_t i = 0; i < num_boundaries; ++i) {
partition_range.push_back(
TypedValue(kVarChar,
kRangeBoundaryStrings[i],
std::strlen(kRangeBoundaryStrings[i]) + 1));
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(TypeFactory::GetType(kVarChar, 20, false), 4, 0, move(partition_range)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeId());
const char *kSampleStrings[] = {"apple",
"halloween",
"mango",
"turkey",
"elephant",
"sathyam",
"zyxw",
"zorgonz"};
const partition_id kExpectedPartitions[] = {0, 1, 2, 2, 1, 2, 3, 3};
const size_t num_strings = sizeof(kExpectedPartitions) / sizeof(kExpectedPartitions[0]);
// Check if the partition id returned by the Range Partition Scheme for
// variable length strings is the same as the partition id into which it
// is supposed to be based on the partition boundaries that we have defined.
for (size_t i = 0; i < num_strings; ++i) {
EXPECT_EQ(kExpectedPartitions[i],
partition_scheme_header->getPartitionId(
TypedValue(kVarChar,
kSampleStrings[i],
std::strlen(kSampleStrings[i]) + 1)));
}
}
TEST(PartitionSchemeTest, AddBlocksToPartitionTest) {
std::unique_ptr<PartitionScheme> partition_scheme(
new PartitionScheme(new HashPartitionSchemeHeader(4, 0)));
for (int i = 0; i < 10; ++i) {
partition_scheme->addBlockToPartition(i, i % 4);
}
// Compute blocks in each partition.
const std::vector<block_id> blocks_in_partition_zero =
partition_scheme->getBlocksInPartition(0);
const std::vector<block_id> blocks_in_partition_one =
partition_scheme->getBlocksInPartition(1);
const std::vector<block_id> blocks_in_partition_two =
partition_scheme->getBlocksInPartition(2);
const std::vector<block_id> blocks_in_partition_three =
partition_scheme->getBlocksInPartition(3);
EXPECT_EQ(4u, partition_scheme->getPartitionSchemeHeader().getNumPartitions());
EXPECT_EQ(0, partition_scheme->getPartitionSchemeHeader().getPartitionAttributeId());
// Check if the blocks are present in the partitions that we
// expect them to be based on where we inserted them.
EXPECT_NE(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
0));
EXPECT_NE(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
4));
EXPECT_NE(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
8));
EXPECT_NE(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 1));
EXPECT_NE(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 5));
EXPECT_NE(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 9));
EXPECT_NE(
blocks_in_partition_two.end(),
std::find(
blocks_in_partition_two.begin(), blocks_in_partition_two.end(), 2));
EXPECT_NE(
blocks_in_partition_two.end(),
std::find(
blocks_in_partition_two.begin(), blocks_in_partition_two.end(), 6));
EXPECT_NE(blocks_in_partition_three.end(),
std::find(blocks_in_partition_three.begin(),
blocks_in_partition_three.end(),
3));
EXPECT_NE(blocks_in_partition_three.end(),
std::find(blocks_in_partition_three.begin(),
blocks_in_partition_three.end(),
7));
// Check if the number of blocks in a partition are as expected.
EXPECT_EQ(3u, blocks_in_partition_zero.size());
EXPECT_EQ(3u, blocks_in_partition_one.size());
EXPECT_EQ(2u, blocks_in_partition_two.size());
EXPECT_EQ(2u, blocks_in_partition_three.size());
}
TEST(PartitionSchemeTest, RemoveBlocksFromPartitionTest) {
std::unique_ptr<PartitionScheme> partition_scheme(
new PartitionScheme(new HashPartitionSchemeHeader(4, 0)));
for (int i = 0; i < 10; ++i) {
partition_scheme->addBlockToPartition(i, i % 4);
}
EXPECT_EQ(4u, partition_scheme->getPartitionSchemeHeader().getNumPartitions());
EXPECT_EQ(0, partition_scheme->getPartitionSchemeHeader().getPartitionAttributeId());
// remove block 0 from partition 0
partition_scheme->removeBlockFromPartition(0, 0);
const std::vector<block_id> blocks_in_partition_zero =
partition_scheme->getBlocksInPartition(0);
// check if block 0 is removed from partition 0
EXPECT_EQ(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
0));
// Check if block 4 is still present in partition zero.
EXPECT_NE(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
4));
// Check if block 8 is still present in partition zero.
EXPECT_NE(blocks_in_partition_zero.end(),
std::find(blocks_in_partition_zero.begin(),
blocks_in_partition_zero.end(),
8));
EXPECT_EQ(2u, blocks_in_partition_zero.size());
// remove block 5 from partition 1
partition_scheme->removeBlockFromPartition(5, 1);
const std::vector<block_id> blocks_in_partition_one =
partition_scheme->getBlocksInPartition(1);
EXPECT_NE(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 1));
// check if block 5 is not present in partition 1
EXPECT_EQ(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 5));
// Check if block 9 is still present in partition one.
EXPECT_NE(
blocks_in_partition_one.end(),
std::find(
blocks_in_partition_one.begin(), blocks_in_partition_one.end(), 9));
EXPECT_EQ(2u, blocks_in_partition_one.size());
// remove block 2 from partition 2
partition_scheme->removeBlockFromPartition(2, 2);
const std::vector<block_id> blocks_in_partition_two =
partition_scheme->getBlocksInPartition(2);
// check if block 2 is removed from partition 2
EXPECT_EQ(
blocks_in_partition_two.end(),
std::find(
blocks_in_partition_two.begin(), blocks_in_partition_two.end(), 2));
// Check if block 6 is still present in partition two.
EXPECT_NE(
blocks_in_partition_two.end(),
std::find(
blocks_in_partition_two.begin(), blocks_in_partition_two.end(), 6));
EXPECT_EQ(1u, blocks_in_partition_two.size());
// remove block 7 from partition 3
partition_scheme->removeBlockFromPartition(7, 3);
const std::vector<block_id> blocks_in_partition_three =
partition_scheme->getBlocksInPartition(3);
// Check if block 3 is still present in partition three.
EXPECT_NE(blocks_in_partition_three.end(),
std::find(blocks_in_partition_three.begin(),
blocks_in_partition_three.end(),
3));
// check if block 7 is removed from partition 3
EXPECT_EQ(blocks_in_partition_three.end(),
std::find(blocks_in_partition_three.begin(),
blocks_in_partition_three.end(),
7));
EXPECT_EQ(1u, blocks_in_partition_three.size());
}
TEST(PartitionSchemeTest, CheckHashPartitionSchemeSerialization) {
const std::size_t num_partitions = 4;
std::unique_ptr<PartitionScheme> part_scheme(
new PartitionScheme(new HashPartitionSchemeHeader(num_partitions, 0)));
// Add some blocks to each partition.
for (int i = 0; i < 10; ++i) {
part_scheme->addBlockToPartition(i, i % num_partitions);
}
std::unique_ptr<PartitionScheme> part_scheme_from_proto;
part_scheme_from_proto.reset(
PartitionScheme::ReconstructFromProto(part_scheme->getProto()));
const PartitionSchemeHeader &header = part_scheme->getPartitionSchemeHeader();
const PartitionSchemeHeader &header_from_proto = part_scheme_from_proto->getPartitionSchemeHeader();
// Check the partition type
EXPECT_EQ(header.getPartitionType(),
header_from_proto.getPartitionType());
// Check number of partitions
EXPECT_EQ(header.getNumPartitions(),
header_from_proto.getNumPartitions());
// Check the partition attribute id
EXPECT_EQ(header.getPartitionAttributeId(),
header_from_proto.getPartitionAttributeId());
// Check the block in each partition
for (partition_id part_id = 0; part_id < num_partitions; ++part_id) {
// Collect the blocks from C++ Partition Scheme object.
std::vector<block_id> blocks_in_part_scheme =
part_scheme->getBlocksInPartition(part_id);
// Collect the blocks from Partition Scheme's protocol buffer.
std::vector<block_id> blocks_in_part_scheme_from_proto =
part_scheme_from_proto->getBlocksInPartition(part_id);
// Sort both these vector of block ids so that we can compare them.
std::sort(blocks_in_part_scheme.begin(), blocks_in_part_scheme.end());
std::sort(blocks_in_part_scheme_from_proto.begin(),
blocks_in_part_scheme_from_proto.end());
// Compare the two sorted lists to check if they are equal.
EXPECT_EQ(blocks_in_part_scheme, blocks_in_part_scheme_from_proto);
}
}
TEST(PartitionSchemeTest, CheckRangePartitionSchemeSerialization) {
const Type &type = TypeFactory::GetType(kInt);
const std::size_t num_partitions = 4;
std::vector<TypedValue> partition_range;
// Partition boundaries are 0, 10, 20.
// Last partition can hold upto infinity.
// First partition can hold from -infinity to -1.
for (std::size_t i = 0; i < num_partitions - 1; ++i) {
partition_range.push_back(TypedValue(static_cast<int>(i * 10)));
}
std::unique_ptr<PartitionScheme> part_scheme(
new PartitionScheme(
new RangePartitionSchemeHeader(type, num_partitions, 0, move(partition_range))));
for (int i = 0; i < 10; ++i) {
part_scheme->addBlockToPartition(i * 5, i % num_partitions);
}
std::unique_ptr<PartitionScheme> part_scheme_from_proto;
part_scheme_from_proto.reset(
PartitionScheme::ReconstructFromProto(part_scheme->getProto()));
const PartitionSchemeHeader &header = part_scheme->getPartitionSchemeHeader();
const PartitionSchemeHeader &header_from_proto = part_scheme_from_proto->getPartitionSchemeHeader();
// Check the partition type
EXPECT_EQ(header.getPartitionType(),
header_from_proto.getPartitionType());
// Check number of partitions
EXPECT_EQ(header.getNumPartitions(),
header_from_proto.getNumPartitions());
// Check the partition attribute id
EXPECT_EQ(header.getPartitionAttributeId(),
header_from_proto.getPartitionAttributeId());
// Check the partition range boundaries' size.
const std::vector<TypedValue> &range_boundaries_part_scheme =
static_cast<const RangePartitionSchemeHeader&>(header).getPartitionRangeBoundaries();
const std::vector<TypedValue> &range_boundaries_part_scheme_from_proto =
static_cast<const RangePartitionSchemeHeader&>(header_from_proto).getPartitionRangeBoundaries();
EXPECT_EQ(range_boundaries_part_scheme.size(),
range_boundaries_part_scheme_from_proto.size());
// Check the partition range boundaries' values.
const Comparison &equal_comparison_op(EqualComparison::Instance());
std::unique_ptr<UncheckedComparator> equal_unchecked_comparator;
equal_unchecked_comparator.reset(
equal_comparison_op.makeUncheckedComparatorForTypes(
TypeFactory::GetType(kInt), TypeFactory::GetType(kInt)));
for (std::size_t i = 0; i < range_boundaries_part_scheme.size(); ++i) {
EXPECT_TRUE(equal_unchecked_comparator->compareTypedValues(
range_boundaries_part_scheme[i],
range_boundaries_part_scheme_from_proto[i]));
}
// Check the blocks in each partition from both the Partition Scheme's
// C++ object and protocol buffer.
for (partition_id part_id = 0; part_id < num_partitions; ++part_id) {
std::vector<block_id> blocks_in_part_scheme =
part_scheme->getBlocksInPartition(part_id);
std::vector<block_id> blocks_in_part_scheme_from_proto =
part_scheme_from_proto->getBlocksInPartition(part_id);
std::sort(blocks_in_part_scheme.begin(), blocks_in_part_scheme.end());
std::sort(blocks_in_part_scheme_from_proto.begin(),
blocks_in_part_scheme_from_proto.end());
EXPECT_EQ(blocks_in_part_scheme, blocks_in_part_scheme_from_proto);
}
}
TEST(PartitionSchemeTest, CheckBlocksInPartitionTest) {
std::unique_ptr<PartitionScheme> partition_scheme;
constexpr std::size_t kNumBlocks = 10;
constexpr std::size_t kNumPartitions = 4;
constexpr attribute_id kPartitioningAttribute = 0;
// Create a partition scheme object.
partition_scheme.reset(
new PartitionScheme(new HashPartitionSchemeHeader(kNumPartitions, kPartitioningAttribute)));
// Add blocks to different partitions.
for (std::size_t block_id = 0; block_id < kNumBlocks; ++block_id) {
partition_scheme->addBlockToPartition(block_id,
block_id % kNumPartitions);
}
const PartitionSchemeHeader &header = partition_scheme->getPartitionSchemeHeader();
// Check the number of partitions and the partitioning attribute.
EXPECT_EQ(kNumPartitions, header.getNumPartitions());
EXPECT_EQ(kPartitioningAttribute, header.getPartitionAttributeId());
// Check if the blocks are correctly assigned to its partitions.
EXPECT_EQ(0u, partition_scheme->getPartitionForBlock(0));
EXPECT_EQ(1u, partition_scheme->getPartitionForBlock(1));
EXPECT_EQ(2u, partition_scheme->getPartitionForBlock(2));
EXPECT_EQ(3u, partition_scheme->getPartitionForBlock(3));
EXPECT_EQ(0u, partition_scheme->getPartitionForBlock(4));
EXPECT_EQ(1u, partition_scheme->getPartitionForBlock(5));
EXPECT_EQ(2u, partition_scheme->getPartitionForBlock(6));
EXPECT_EQ(3u, partition_scheme->getPartitionForBlock(7));
EXPECT_EQ(0u, partition_scheme->getPartitionForBlock(8));
EXPECT_EQ(1u, partition_scheme->getPartitionForBlock(9));
// Block that is not present in any partition.
EXPECT_EQ(std::numeric_limits<partition_id>::max(),
partition_scheme->getPartitionForBlock(100));
}
} // namespace quickstep