blob: e4320b29a48c134751b55788a5b54ac3105566e9 [file]
/*
* 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 "paimon/common/memory/memory_segment_utils.h"
#include <cstdlib>
#include <string>
#include "gtest/gtest.h"
#include "paimon/testing/utils/testharness.h"
namespace paimon::test {
TEST(MemorySegmentUtilsTest, TestSetAndGetValue) {
auto pool = GetDefaultPool();
for (auto single_segment_size : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 128}) {
std::vector<MemorySegment> segments;
segments.reserve(50);
for (size_t i = 0; i < 50; i++) {
segments.push_back(
MemorySegment::Wrap(Bytes::AllocateBytes(single_segment_size, pool.get())));
}
int32_t offset = 0;
MemorySegmentUtils::SetValue<int32_t>(&segments, offset, 233);
ASSERT_EQ(233, MemorySegmentUtils::GetValue<int32_t>(segments, offset));
offset += sizeof(int32_t);
MemorySegmentUtils::SetValue<int64_t>(&segments, offset, 23333333333);
ASSERT_EQ(23333333333, MemorySegmentUtils::GetValue<int64_t>(segments, offset));
offset += sizeof(int64_t);
MemorySegmentUtils::SetValue<float>(&segments, offset, 233.3);
ASSERT_NEAR(233.3, MemorySegmentUtils::GetValue<float>(segments, offset), 0.001);
offset += sizeof(float);
MemorySegmentUtils::SetValue<double>(&segments, offset, 244.3);
ASSERT_NEAR(244.3, MemorySegmentUtils::GetValue<double>(segments, offset), 0.001);
offset += sizeof(double);
MemorySegmentUtils::SetValue<int16_t>(&segments, offset, 5564);
ASSERT_EQ(5564, MemorySegmentUtils::GetValue<int16_t>(segments, offset));
offset += sizeof(int16_t);
MemorySegmentUtils::SetValue<char>(&segments, offset, 123);
ASSERT_EQ(123, MemorySegmentUtils::GetValue<char>(segments, offset));
offset += sizeof(char);
MemorySegmentUtils::SetValue<bool>(&segments, offset, true);
ASSERT_EQ(true, MemorySegmentUtils::GetValue<bool>(segments, offset));
ASSERT_EQ(233, MemorySegmentUtils::GetValue<int32_t>(segments, 0));
}
}
TEST(MemorySegmentUtilsTest, TestCopyFromBytesAndGetBytes) {
auto pool = GetDefaultPool();
int32_t str_size = 1024;
std::string test_string1, test_string2;
test_string1.reserve(str_size);
test_string2.reserve(str_size);
for (int32_t j = 0; j < str_size; j++) {
test_string1 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
test_string2 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
}
test_string2 += test_string1;
std::shared_ptr<Bytes> bytes1 = Bytes::AllocateBytes(test_string1, pool.get());
std::shared_ptr<Bytes> bytes2 = Bytes::AllocateBytes(test_string2, pool.get());
std::vector<MemorySegment> segs = {MemorySegment::AllocateHeapMemory(str_size, pool.get())};
MemorySegmentUtils::CopyFromBytes(&segs, 0, *bytes1, 0, test_string1.size());
PAIMON_UNIQUE_PTR<Bytes> bytes_serialize =
MemorySegmentUtils::CopyToBytes(segs, 0, test_string1.size(), pool.get());
auto bytes_get = MemorySegmentUtils::GetBytes(segs, /*base_offset=*/0,
/*size_in_bytes=*/str_size, pool.get());
ASSERT_EQ(*bytes_get, *bytes1);
std::string str_serialize = std::string(bytes_serialize->data(), bytes_serialize->size());
ASSERT_EQ(test_string1, str_serialize);
// test MultiSegments
std::vector<MemorySegment> segs2 = {MemorySegment::AllocateHeapMemory(str_size, pool.get()),
MemorySegment::AllocateHeapMemory(str_size, pool.get())};
MemorySegmentUtils::CopyFromBytes(&segs2, 0, *bytes2, 0, test_string2.size());
PAIMON_UNIQUE_PTR<Bytes> bytes_serialize2 =
MemorySegmentUtils::CopyToBytes(segs2, 0, test_string2.size(), pool.get());
std::string str_serialize2 = std::string(bytes_serialize2->data(), bytes_serialize2->size());
ASSERT_EQ(test_string2, str_serialize2);
std::shared_ptr<Bytes> bytes_serialize3 = MemorySegmentUtils::GetBytes(
segs2, test_string2.size() - test_string1.size(), test_string1.size(), pool.get());
std::string str_serialize3 = std::string(bytes_serialize3->data(), bytes_serialize3->size());
ASSERT_EQ(test_string1, str_serialize3);
}
TEST(MemorySegmentUtilsTest, TestCopyToUnsafe) {
auto pool = GetDefaultPool();
int32_t str_size = 1024;
std::string test_string1, test_string2;
test_string1.reserve(str_size);
test_string2.reserve(str_size);
for (int32_t j = 0; j < str_size; j++) {
test_string1 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
test_string2 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
}
test_string2 += test_string1;
std::shared_ptr<Bytes> bytes1 = Bytes::AllocateBytes(test_string1, pool.get());
std::shared_ptr<Bytes> bytes2 = Bytes::AllocateBytes(test_string2, pool.get());
std::vector<MemorySegment> segs = {MemorySegment::AllocateHeapMemory(str_size, pool.get())};
MemorySegmentUtils::CopyFromBytes(&segs, 0, *bytes1, 0, test_string1.size());
std::shared_ptr<Bytes> bytes_serialize = Bytes::AllocateBytes(test_string1.size(), pool.get());
MemorySegmentUtils::CopyToUnsafe(segs, 0, bytes_serialize->data(), test_string1.size());
ASSERT_EQ(test_string1, std::string(bytes_serialize->data(), bytes_serialize->size()));
// test MultiSegments
std::vector<MemorySegment> segs2 = {MemorySegment::AllocateHeapMemory(str_size, pool.get()),
MemorySegment::AllocateHeapMemory(str_size, pool.get())};
MemorySegmentUtils::CopyFromBytes(&segs2, 0, *bytes2, 0, test_string2.size());
std::shared_ptr<Bytes> bytes_serialize2 = Bytes::AllocateBytes(test_string1.size(), pool.get());
MemorySegmentUtils::CopyToUnsafe(segs2, test_string2.size() - test_string1.size(),
bytes_serialize2->data(), test_string1.size());
ASSERT_EQ(test_string1, std::string(bytes_serialize2->data(), bytes_serialize2->size()));
}
TEST(MemorySegmentUtilsTest, TestSetAndUnSet) {
auto pool = GetDefaultPool();
int32_t str_size = 1024;
std::string test_string1, test_string2;
test_string1.reserve(str_size);
test_string2.reserve(str_size);
for (int32_t j = 0; j < str_size; j++) {
test_string1 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
test_string2 += static_cast<char>(paimon::test::RandomNumber(0, 25) + 'a');
}
test_string2 += test_string1;
std::shared_ptr<Bytes> bytes2 = Bytes::AllocateBytes(test_string2, pool.get());
std::vector<MemorySegment> segs = {MemorySegment::AllocateHeapMemory(str_size, pool.get()),
MemorySegment::AllocateHeapMemory(str_size, pool.get())};
MemorySegmentUtils::CopyFromBytes(&segs, 0, *bytes2, 0, test_string2.size());
int32_t index = paimon::test::RandomNumber(0, str_size - 1);
MemorySegmentUtils::BitUnSet(&segs, str_size, index);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, str_size, index));
MemorySegmentUtils::BitSet(&segs, str_size, index);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, str_size, index));
MemorySegmentUtils::BitSet(&segs[0], /*base_offset=*/0, index);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs[0], /*base_offset=*/0, index));
MemorySegmentUtils::BitUnSet(&segs[0], /*base_offset=*/0, index);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs[0], /*base_offset=*/0, index));
}
TEST(MemorySegmentUtilsTest, TestBitSetAndUnSetSingleSegment) {
auto pool = GetDefaultPool();
int32_t segment_size = 128;
std::vector<MemorySegment> segs = {MemorySegment::AllocateHeapMemory(segment_size, pool.get())};
// initially all bits should be 0 after allocation
for (int32_t i = 0; i < 16; i++) {
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, i));
}
// set bits at various indices and verify
MemorySegmentUtils::BitSet(&segs, /*base_offset=*/0, /*index=*/0);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 0));
MemorySegmentUtils::BitSet(&segs, /*base_offset=*/0, /*index=*/7);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 7));
MemorySegmentUtils::BitSet(&segs, /*base_offset=*/0, /*index=*/15);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 15));
// unset and verify
MemorySegmentUtils::BitUnSet(&segs, /*base_offset=*/0, /*index=*/0);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 0));
MemorySegmentUtils::BitUnSet(&segs, /*base_offset=*/0, /*index=*/7);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 7));
// bit 15 should still be set
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 15));
MemorySegmentUtils::BitUnSet(&segs, /*base_offset=*/0, /*index=*/15);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, /*base_offset=*/0, 15));
// test with non-zero base_offset
int32_t base_offset = 10;
MemorySegmentUtils::BitSet(&segs, base_offset, /*index=*/3);
ASSERT_TRUE(MemorySegmentUtils::BitGet(segs, base_offset, 3));
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, base_offset, 2));
MemorySegmentUtils::BitUnSet(&segs, base_offset, /*index=*/3);
ASSERT_FALSE(MemorySegmentUtils::BitGet(segs, base_offset, 3));
}
TEST(MemorySegmentUtilsTest, TestCopyMultiSegmentsFromBytes) {
auto pool = GetDefaultPool();
std::shared_ptr<Bytes> bytes = Bytes::AllocateBytes("abcdef", pool.get());
int32_t segment_size = 10;
std::vector<MemorySegment> segs = {MemorySegment::AllocateHeapMemory(segment_size, pool.get()),
MemorySegment::AllocateHeapMemory(segment_size, pool.get())};
{
MemorySegmentUtils::CopyMultiSegmentsFromBytes(&segs, /*offset=*/3, *bytes,
/*bytes_offset=*/0,
/*num_bytes=*/bytes->size());
auto result_bytes =
MemorySegmentUtils::CopyToBytes(segs, /*offset=*/3,
/*num_bytes=*/bytes->size(), pool.get());
ASSERT_EQ(*bytes, *result_bytes);
}
{
MemorySegmentUtils::CopyMultiSegmentsFromBytes(&segs, /*offset=*/12, *bytes,
/*bytes_offset=*/0,
/*num_bytes=*/bytes->size());
auto result_bytes =
MemorySegmentUtils::CopyToBytes(segs, /*offset=*/12,
/*num_bytes=*/bytes->size(), pool.get());
ASSERT_EQ(*bytes, *result_bytes);
}
}
TEST(MemorySegmentUtilsTest, TestCopyToStream) {
auto pool = GetDefaultPool();
int32_t segment_size = 3;
std::shared_ptr<Bytes> bytes1 = Bytes::AllocateBytes("abc", pool.get());
std::shared_ptr<Bytes> bytes2 = Bytes::AllocateBytes("def", pool.get());
std::vector<MemorySegment> segs = {MemorySegment::Wrap(bytes1), MemorySegment::Wrap(bytes2)};
{
MemorySegmentOutputStream out(/*segment_size=*/segment_size, pool);
ASSERT_OK(MemorySegmentUtils::CopyToStream(segs, /*offset=*/0,
/*size_in_bytes=*/segment_size * 2, &out));
std::shared_ptr<Bytes> expected_bytes = Bytes::AllocateBytes("abcdef", pool.get());
auto bytes =
MemorySegmentUtils::CopyToBytes(out.Segments(), 0, out.CurrentSize(), pool.get());
ASSERT_EQ(*expected_bytes, *bytes);
}
{
MemorySegmentOutputStream out(/*segment_size=*/segment_size, pool);
ASSERT_OK(MemorySegmentUtils::CopyToStream(segs, /*offset=*/2, /*size_in_bytes=*/4, &out));
std::shared_ptr<Bytes> expected_bytes = Bytes::AllocateBytes("cdef", pool.get());
auto bytes =
MemorySegmentUtils::CopyToBytes(out.Segments(), 0, out.CurrentSize(), pool.get());
ASSERT_EQ(*expected_bytes, *bytes);
}
{
MemorySegmentOutputStream out(/*segment_size=*/segment_size, pool);
ASSERT_OK(MemorySegmentUtils::CopyToStream(segs, /*offset=*/4, /*size_in_bytes=*/2, &out));
std::shared_ptr<Bytes> expected_bytes = Bytes::AllocateBytes("ef", pool.get());
auto bytes =
MemorySegmentUtils::CopyToBytes(out.Segments(), 0, out.CurrentSize(), pool.get());
ASSERT_EQ(*expected_bytes, *bytes);
}
}
TEST(MemorySegmentUtilsTest, TestFind) {
auto pool = GetDefaultPool();
std::shared_ptr<Bytes> bytes1 = Bytes::AllocateBytes("abc", pool.get());
std::shared_ptr<Bytes> bytes2 = Bytes::AllocateBytes("def", pool.get());
std::shared_ptr<Bytes> bytes3 = Bytes::AllocateBytes("adef", pool.get());
std::shared_ptr<Bytes> bytes4 = Bytes::AllocateBytes("ghi", pool.get());
std::vector<MemorySegment> segs1 = {MemorySegment::Wrap(bytes1),
MemorySegment::Wrap(bytes2)}; // abcdef
std::vector<MemorySegment> segs2 = {MemorySegment::Wrap(bytes3),
MemorySegment::Wrap(bytes4)}; // adefghi
// find ""
ASSERT_EQ(1, MemorySegmentUtils::Find(segs1, /*offset1=*/1, /*num_bytes1=*/5, segs2,
/*offset2=*/0, /*num_bytes2=*/0));
// find "def"
ASSERT_EQ(3, MemorySegmentUtils::Find(segs1, /*offset1=*/0, /*num_bytes1=*/6, segs2,
/*offset2=*/1, /*num_bytes2=*/3));
// find "defg"
ASSERT_EQ(-1, MemorySegmentUtils::Find(segs1, /*offset1=*/0, /*num_bytes1=*/6, segs2,
/*offset2=*/1, /*num_bytes2=*/4));
// find "de" in "abc" of segs1
ASSERT_EQ(-1, MemorySegmentUtils::Find(segs1, /*offset1=*/0, /*num_bytes1=*/3, segs2,
/*offset2=*/1, /*num_bytes2=*/2));
// find "a" in "abc" of segs1
ASSERT_EQ(0, MemorySegmentUtils::Find(segs1, /*offset1=*/0, /*num_bytes1=*/3, segs2,
/*offset2=*/0, /*num_bytes2=*/1));
}
} // namespace paimon::test