blob: 190978ffb18eae833d8456153f2d1d8f733ba1c7 [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 "utility/CompositeHash.hpp"
#include "gtest/gtest.h"
using std::move;
using std::size_t;
using std::vector;
namespace quickstep {
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->getPartitionAttributeIds().front());
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->getPartitionAttributeIds().front());
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->getPartitionAttributeIds().front());
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->getPartitionAttributeIds().front());
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->getPartitionAttributeIds().front());
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->getPartitionAttributeIds().front());
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, MultiAttributeHashPartitionSchemeHeaderTest) {
const std::size_t num_partitions = 4;
constexpr attribute_id kPartitioningFirstAttribute = 0;
constexpr attribute_id kPartitioningLastAttribute = 2;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new HashPartitionSchemeHeader(num_partitions, { kPartitioningFirstAttribute, kPartitioningLastAttribute }));
EXPECT_EQ(num_partitions, partition_scheme_header->getNumPartitions());
EXPECT_EQ(kPartitioningFirstAttribute, partition_scheme_header->getPartitionAttributeIds().front());
EXPECT_EQ(kPartitioningLastAttribute, partition_scheme_header->getPartitionAttributeIds().back());
const int kSampleInts[] = {
0, 78437883, -2784627};
const double kSampleDoubles[] = {
1.0378, 763624.46343453, -87238497384.3187431894713};
const size_t num_ints = sizeof(kSampleInts) / sizeof(kSampleInts[0]);
for (size_t i = 0; i < num_ints; ++i) {
const PartitionSchemeHeader::PartitionValues values =
{ TypedValue(kSampleInts[i]), TypedValue(kSampleDoubles[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(HashCompositeKey(values) % num_partitions,
partition_scheme_header->getPartitionId(values));
}
}
TEST(PartitionSchemeHeaderTest, IntegerRangePartitionSchemeHeaderTest) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// 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_ranges.push_back({ TypedValue(i * 10) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kInt) }, move(partition_ranges)));
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->getPartitionAttributeIds().front());
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) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// Partition boundaries are 0, 10000, 20000, 30000
for (int i = 0; i < 3; ++i) {
partition_ranges.push_back({ TypedValue(i * INT64_C(10000)) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kLong) }, move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeIds().front());
// 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) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// Partition boundaries are 0.0, 10.0, 20.0
for (int i = 0; i < 3; ++i) {
partition_ranges.push_back({ TypedValue(i * 10.0f) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kFloat) }, move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeIds().front());
// 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) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// Partition boundaries are 0.00000, 10.00000, 20.00000
for (int i = 0; i < 3; ++i) {
partition_ranges.push_back({ TypedValue(i * 10.00000) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kDouble) }, move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeIds().front());
// 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) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// 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_ranges.push_back(
{ TypedValue(kChar, kRangeBoundaryStrings[i], std::strlen(kRangeBoundaryStrings[i]) + 1) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kChar, 20, false) }, move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeIds().front());
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) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// 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_ranges.push_back(
{ TypedValue(kVarChar, kRangeBoundaryStrings[i], std::strlen(kRangeBoundaryStrings[i]) + 1) });
}
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { 0 }, { &TypeFactory::GetType(kVarChar, 20, false) }, move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(0, partition_scheme_header->getPartitionAttributeIds().front());
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(PartitionSchemeHeaderTest, MultiAttributeRangePartitionSchemeHeaderTest) {
vector<PartitionSchemeHeader::PartitionValues> partition_ranges;
// Partition boundaries are { 0, 0.00000 }, { 10, 10.0000 }, { 20, 20.00000 }
// Last partition can hold upto infinity.
// First partition can hold from { -infinity, -infinity } to { 0, -2^(-1074) }.
for (int i = 0; i < 3; ++i) {
partition_ranges.push_back({ TypedValue(i * 10), TypedValue(i * 10.00000) });
}
constexpr attribute_id kPartitioningFirstAttribute = 0;
constexpr attribute_id kPartitioningLastAttribute = 2;
std::unique_ptr<PartitionSchemeHeader> partition_scheme_header(
new RangePartitionSchemeHeader(4, { kPartitioningFirstAttribute, kPartitioningLastAttribute },
{ &TypeFactory::GetType(kInt), &TypeFactory::GetType(kDouble) },
move(partition_ranges)));
EXPECT_EQ(4u, partition_scheme_header->getNumPartitions());
EXPECT_EQ(kPartitioningFirstAttribute, partition_scheme_header->getPartitionAttributeIds().front());
EXPECT_EQ(kPartitioningLastAttribute, partition_scheme_header->getPartitionAttributeIds().back());
// Check if the partition id returned by the Range Partition Scheme for
// { int, double } 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(0u, partition_scheme_header->getPartitionId({ TypedValue(-70), TypedValue(30.567866347563) }));
EXPECT_EQ(0u, partition_scheme_header->getPartitionId({ TypedValue(0), TypedValue(-4.57583978935689) }));
EXPECT_EQ(1u, partition_scheme_header->getPartitionId({ TypedValue(6), TypedValue(15.034248758978936) }));
EXPECT_EQ(2u, partition_scheme_header->getPartitionId({ TypedValue(10), TypedValue(10.00000000287489) }));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId({ TypedValue(20), TypedValue(20.23249859403750) }));
EXPECT_EQ(3u, partition_scheme_header->getPartitionId({ TypedValue(300), TypedValue(-70.38454985893768738) }));
}
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().getPartitionAttributeIds().front());
// 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().getPartitionAttributeIds().front());
// 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.getPartitionAttributeIds(),
header_from_proto.getPartitionAttributeIds());
// 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, CheckRandomPartitionSchemeSerialization) {
const std::size_t num_partitions = 4;
std::unique_ptr<PartitionScheme> part_scheme(
new PartitionScheme(new RandomPartitionSchemeHeader(num_partitions)));
// 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.getPartitionAttributeIds(),
header_from_proto.getPartitionAttributeIds());
// 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);
}
}
// TODO(quickstep-team): Add back CheckRangePartitionSchemeSerialization test
// due to QUICKSTEP-86.
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.getPartitionAttributeIds().front());
// 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