starrocks/be/test/block_cache/block_cache_test.cpp

217 lines
6.9 KiB
C++

// Copyright 2021-present StarRocks, Inc. All rights reserved.
//
// Licensed 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
//
// https://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 "block_cache/block_cache.h"
#include <gtest/gtest.h>
#include <cstring>
#include "common/logging.h"
#include "common/statusor.h"
#include "fs/fs_util.h"
namespace starrocks {
static const size_t block_size = 1024 * 1024;
class BlockCacheTest : public ::testing::Test {
protected:
static void SetUpTestCase() { ASSERT_TRUE(fs::create_directories("./ut_dir/block_disk_cache").ok()); }
static void TearDownTestCase() { ASSERT_TRUE(fs::remove_all("./ut_dir").ok()); }
void SetUp() override {}
void TearDown() override {}
};
TEST_F(BlockCacheTest, auto_create_disk_cache_path) {
std::unique_ptr<BlockCache> cache(new BlockCache);
const size_t block_size = 1024 * 1024;
CacheOptions options;
options.mem_space_size = 20 * 1024 * 1024;
size_t quota = 500 * 1024 * 1024;
options.disk_spaces.push_back({.path = "./ut_dir/final_entry_not_exist", .size = quota});
options.block_size = block_size;
options.max_concurrent_inserts = 100000;
#ifdef WITH_STARCACHE
options.engine = "starcache";
#else
options.engine = "cachelib";
#endif
Status status = cache->init(options);
ASSERT_TRUE(status.ok());
const size_t batch_size = block_size - 1234;
const size_t rounds = 3;
const std::string cache_key = "test_file";
// write cache
off_t offset = 0;
for (size_t i = 0; i < rounds; ++i) {
char ch = 'a' + i % 26;
std::string value(batch_size, ch);
Status st = cache->write_cache(cache_key + std::to_string(i), 0, batch_size, value.c_str());
ASSERT_TRUE(st.ok());
offset += batch_size;
}
// read cache
offset = 0;
for (size_t i = 0; i < rounds; ++i) {
char ch = 'a' + i % 26;
std::string expect_value(batch_size, ch);
char value[batch_size] = {0};
auto res = cache->read_cache(cache_key + std::to_string(i), 0, batch_size, value);
ASSERT_TRUE(res.status().ok());
ASSERT_EQ(memcmp(value, expect_value.c_str(), batch_size), 0);
offset += batch_size;
}
cache->shutdown();
}
#ifdef WITH_STARCACHE
TEST_F(BlockCacheTest, hybrid_cache) {
std::unique_ptr<BlockCache> cache(new BlockCache);
const size_t block_size = 1024 * 1024;
CacheOptions options;
options.mem_space_size = 10 * 1024 * 1024;
size_t quota = 500 * 1024 * 1024;
options.disk_spaces.push_back({.path = "./ut_dir/block_disk_cache", .size = quota});
options.block_size = block_size;
options.max_concurrent_inserts = 100000;
options.engine = "starcache";
Status status = cache->init(options);
ASSERT_TRUE(status.ok());
const size_t batch_size = block_size - 1234;
const size_t rounds = 20;
const std::string cache_key = "test_file";
// write cache
off_t offset = 0;
for (size_t i = 0; i < rounds; ++i) {
char ch = 'a' + i % 26;
std::string value(batch_size, ch);
Status st = cache->write_cache(cache_key + std::to_string(i), 0, batch_size, value.c_str());
ASSERT_TRUE(st.ok());
offset += batch_size;
}
// read cache
offset = 0;
for (size_t i = 0; i < rounds; ++i) {
char ch = 'a' + i % 26;
std::string expect_value(batch_size, ch);
char value[batch_size] = {0};
auto res = cache->read_cache(cache_key + std::to_string(i), 0, batch_size, value);
ASSERT_TRUE(res.status().ok());
ASSERT_EQ(memcmp(value, expect_value.c_str(), batch_size), 0);
offset += batch_size;
}
// remove cache
char value[1024] = {0};
status = cache->remove_cache(cache_key, 0, batch_size);
ASSERT_TRUE(status.ok());
auto res = cache->read_cache(cache_key, 0, batch_size, value);
ASSERT_TRUE(res.status().is_not_found());
// not found
res = cache->read_cache(cache_key, block_size * 1000, batch_size, value);
ASSERT_TRUE(res.status().is_not_found());
cache->shutdown();
}
TEST_F(BlockCacheTest, write_with_overwrite_option) {
std::unique_ptr<BlockCache> cache(new BlockCache);
const size_t block_size = 1024 * 1024;
CacheOptions options;
options.mem_space_size = 20 * 1024 * 1024;
options.block_size = block_size;
options.max_concurrent_inserts = 100000;
options.engine = "starcache";
Status status = cache->init(options);
ASSERT_TRUE(status.ok());
const size_t cache_size = 1024;
const std::string cache_key = "test_file";
std::string value(cache_size, 'a');
Status st = cache->write_cache(cache_key, 0, cache_size, value.c_str());
ASSERT_TRUE(st.ok());
std::string value2(cache_size, 'b');
st = cache->write_cache(cache_key, 0, cache_size, value2.c_str(), 0, true);
ASSERT_TRUE(st.ok());
char rvalue[cache_size] = {0};
auto res = cache->read_cache(cache_key, 0, cache_size, rvalue);
ASSERT_TRUE(res.status().ok());
std::string expect_value(cache_size, 'b');
ASSERT_EQ(memcmp(rvalue, expect_value.c_str(), cache_size), 0);
std::string value3(cache_size, 'c');
st = cache->write_cache(cache_key, 0, cache_size, value3.c_str(), 0, false);
ASSERT_TRUE(st.is_already_exist());
cache->shutdown();
}
#endif
#ifdef WITH_CACHELIB
TEST_F(BlockCacheTest, custom_lru_insertion_point) {
std::unique_ptr<BlockCache> cache(new BlockCache);
const size_t block_size = 1024 * 1024;
CacheOptions options;
options.mem_space_size = 20 * 1024 * 1024;
options.block_size = block_size;
options.max_concurrent_inserts = 100000;
options.engine = "cachelib";
// insert in the 1/2 of the lru list
options.lru_insertion_point = 1;
Status status = cache->init(options);
ASSERT_TRUE(status.ok());
const size_t rounds = 20;
const size_t batch_size = block_size;
const std::string cache_key = "test_file";
// write cache
// only 12 blocks can be cached
for (size_t i = 0; i < rounds; ++i) {
char ch = 'a' + i % 26;
std::string value(batch_size, ch);
Status st = cache->write_cache(cache_key + std::to_string(i), 0, batch_size, value.c_str());
ASSERT_TRUE(st.ok());
}
// read cache
// with the 1/2 lru insertion point, the test_file1 items will not be evicted
char value[batch_size] = {0};
auto res = cache->read_cache(cache_key + std::to_string(1), 0, batch_size, value);
ASSERT_TRUE(res.status().ok());
cache->shutdown();
}
#endif
} // namespace starrocks