ClickHouse/src/Interpreters/tests/gtest_lru_file_cache.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

689 lines
27 KiB
C++
Raw Normal View History

2022-01-13 11:57:56 +00:00
#include <iomanip>
#include <iostream>
#include <gtest/gtest.h>
2022-08-31 19:07:39 +00:00
#include <Interpreters/Cache/FileCache.h>
2022-08-26 17:23:46 +00:00
#include <Interpreters/Cache/FileSegment.h>
2022-01-21 15:39:34 +00:00
#include <Common/CurrentThread.h>
2022-01-13 11:57:56 +00:00
#include <Common/filesystemHelpers.h>
2022-09-06 11:30:02 +00:00
#include <Interpreters/Cache/FileCacheSettings.h>
2022-12-06 10:04:15 +00:00
#include <Interpreters/TemporaryDataOnDisk.h>
2022-01-24 09:32:39 +00:00
#include <Common/tests/gtest_global_context.h>
2022-01-21 15:39:34 +00:00
#include <Common/SipHash.h>
#include <Common/hex.h>
#include <Interpreters/Context.h>
#include <IO/ReadHelpers.h>
2022-01-13 11:57:56 +00:00
#include <IO/WriteHelpers.h>
#include <filesystem>
#include <thread>
2022-12-06 10:04:15 +00:00
#include <DataTypes/DataTypesNumber.h>
2022-12-06 17:27:05 +00:00
#include <Poco/ConsoleChannel.h>
2022-12-06 10:04:15 +00:00
#include <Disks/IO/CachedOnDiskWriteBufferFromFile.h>
2022-12-06 17:27:05 +00:00
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
2022-11-21 17:45:59 +00:00
2022-01-13 11:57:56 +00:00
namespace fs = std::filesystem;
2022-12-06 10:04:15 +00:00
using namespace DB;
2022-01-13 11:57:56 +00:00
2022-12-06 10:04:15 +00:00
static constexpr auto TEST_LOG_LEVEL = "debug";
2022-01-13 11:57:56 +00:00
void printRanges(const auto & segments)
{
std::cerr << "\nHaving file segments: ";
for (const auto & segment : segments)
std::cerr << '\n' << segment->range().toString() << " (state: " + DB::FileSegment::stateToString(segment->state()) + ")" << "\n";
2022-01-13 11:57:56 +00:00
}
2022-08-10 05:50:30 +00:00
String getFileSegmentPath(const String & base_path, const DB::FileCache::Key & key, size_t offset)
2022-01-21 15:39:34 +00:00
{
2022-05-14 12:26:04 +00:00
auto key_str = key.toString();
2022-01-21 15:39:34 +00:00
return fs::path(base_path) / key_str.substr(0, 3) / key_str / DB::toString(offset);
2022-01-13 11:57:56 +00:00
}
2023-01-05 20:32:40 +00:00
void download(const std::string & cache_base_path, DB::FileSegment & file_segment)
2022-01-13 11:57:56 +00:00
{
2023-01-05 20:32:40 +00:00
const auto & key = file_segment.key();
size_t size = file_segment.range().size();
2022-01-13 11:57:56 +00:00
2022-05-14 12:26:04 +00:00
auto key_str = key.toString();
2022-01-21 15:39:34 +00:00
auto subdir = fs::path(cache_base_path) / key_str.substr(0, 3) / key_str;
2022-01-13 11:57:56 +00:00
if (!fs::exists(subdir))
fs::create_directories(subdir);
std::string data(size, '0');
2023-01-05 20:32:40 +00:00
file_segment.write(data.data(), size, file_segment.getCurrentWriteOffset());
}
using Range = FileSegment::Range;
using Ranges = std::vector<Range>;
using State = FileSegment::State;
using States = std::vector<State>;
using Holder = FileSegmentsHolder;
using HolderPtr = FileSegmentsHolderPtr;
fs::path caches_dir = fs::current_path() / "lru_cache_test";
std::string cache_base_path = caches_dir / "cache1" / "";
void assertEqual(const HolderPtr & holder, const Ranges & expected_ranges, const States & expected_states = {})
{
std::cerr << "Holder: " << holder->toString() << "\n";
ASSERT_EQ(holder->size(), expected_ranges.size());
if (!expected_states.empty())
ASSERT_EQ(holder->size(), expected_states.size());
auto get_expected_state = [&](size_t i)
{
if (expected_states.empty())
return State::DOWNLOADED;
else
return expected_states[i];
};
size_t i = 0;
for (const auto & file_segment : *holder)
{
ASSERT_EQ(file_segment->range(), expected_ranges[i]);
ASSERT_EQ(file_segment->state(), get_expected_state(i));
++i;
}
2022-01-21 15:39:34 +00:00
}
2023-01-05 20:32:40 +00:00
FileSegment & get(const HolderPtr & holder, int i)
2022-01-21 15:39:34 +00:00
{
2023-01-05 20:32:40 +00:00
auto it = std::next(holder->begin(), i);
if (it == holder->end())
std::terminate();
return **it;
}
void download(FileSegment & file_segment)
{
std::cerr << "Downloading range " << file_segment.range().toString() << "\n";
ASSERT_EQ(file_segment.getOrSetDownloader(), FileSegment::getCallerId());
ASSERT_EQ(file_segment.state(), State::DOWNLOADING);
ASSERT_EQ(file_segment.getDownloadedSize(), 0);
ASSERT_TRUE(file_segment.reserve(file_segment.range().size()));
2022-12-06 10:04:15 +00:00
download(cache_base_path, file_segment);
2023-01-05 20:32:40 +00:00
ASSERT_EQ(file_segment.state(), State::DOWNLOADING);
file_segment.complete();
ASSERT_EQ(file_segment.state(), State::DOWNLOADED);
2022-01-13 11:57:56 +00:00
}
2023-01-05 20:32:40 +00:00
void assertDownloadFails(FileSegment & file_segment)
{
ASSERT_EQ(file_segment.getOrSetDownloader(), FileSegment::getCallerId());
ASSERT_EQ(file_segment.getDownloadedSize(), 0);
ASSERT_FALSE(file_segment.reserve(file_segment.range().size()));
file_segment.complete();
}
void download(const HolderPtr & holder)
2022-01-13 11:57:56 +00:00
{
for (auto it = holder->begin(); it != holder->end(); ++it)
2022-01-13 11:57:56 +00:00
{
2023-01-05 20:32:40 +00:00
download(**it);
2022-01-13 11:57:56 +00:00
}
}
2022-12-06 10:04:15 +00:00
class FileCacheTest : public ::testing::Test
2022-11-23 14:48:51 +00:00
{
2022-12-06 10:04:15 +00:00
public:
static void setupLogs(const std::string & level)
{
Poco::AutoPtr<Poco::ConsoleChannel> channel(new Poco::ConsoleChannel(std::cerr));
Poco::Logger::root().setChannel(channel);
Poco::Logger::root().setLevel(level);
}
2022-12-06 10:04:15 +00:00
void SetUp() override
{
if(const char * test_log_level = std::getenv("TEST_LOG_LEVEL")) // NOLINT(concurrency-mt-unsafe)
setupLogs(test_log_level);
else
setupLogs(TEST_LOG_LEVEL);
if (fs::exists(cache_base_path))
fs::remove_all(cache_base_path);
fs::create_directories(cache_base_path);
}
void TearDown() override
{
if (fs::exists(cache_base_path))
fs::remove_all(cache_base_path);
}
};
TEST_F(FileCacheTest, get)
{
2022-01-21 15:39:34 +00:00
DB::ThreadStatus thread_status;
/// To work with cache need query_id and query context.
2022-06-06 08:48:30 +00:00
std::string query_id = "query_id";
2022-01-24 09:32:39 +00:00
auto query_context = DB::Context::createCopy(getContext().context);
2022-01-21 15:39:34 +00:00
query_context->makeQueryContext();
2022-06-06 08:48:30 +00:00
query_context->setCurrentQueryId(query_id);
2022-01-21 15:39:34 +00:00
DB::CurrentThread::QueryScope query_scope_holder(query_context);
2022-03-25 17:31:15 +00:00
DB::FileCacheSettings settings;
settings.max_size = 30;
settings.max_elements = 5;
2022-01-13 11:57:56 +00:00
{
2023-01-05 20:32:40 +00:00
std::cerr << "Step 1\n";
auto cache = FileCache(cache_base_path, settings);
2022-08-31 16:07:40 +00:00
cache.initialize();
auto key = cache.createKeyForPath("key1");
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
{
2022-09-06 11:30:02 +00:00
auto holder = cache.getOrSet(key, 0, 10, {}); /// Add range [0, 9]
2023-01-05 20:32:40 +00:00
assertEqual(holder, { Range(0, 9) }, { State::EMPTY });
download(holder->front());
assertEqual(holder, { Range(0, 9) }, { State::DOWNLOADED });
2022-08-31 16:07:40 +00:00
}
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [__________]
/// ^ ^
/// 0 9
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(0, 9) });
assertEqual(cache.dumpQueue(), { Range(0, 9) });
2022-08-31 16:07:40 +00:00
ASSERT_EQ(cache.getFileSegmentsNum(), 1);
ASSERT_EQ(cache.getUsedCacheSize(), 10);
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 2\n";
2022-08-31 16:07:40 +00:00
{
/// Want range [5, 14], but [0, 9] already in cache, so only [10, 14] will be put in cache.
2022-09-06 11:30:02 +00:00
auto holder = cache.getOrSet(key, 5, 10, {});
2023-01-05 20:32:40 +00:00
assertEqual(holder, { Range(0, 9), Range(10, 14) }, { State::DOWNLOADED, State::EMPTY });
download(get(holder, 1));
assertEqual(holder, { Range(0, 9), Range(10, 14) }, { State::DOWNLOADED, State::DOWNLOADED });
2022-08-31 16:07:40 +00:00
}
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [__________][_____]
/// ^ ^^ ^
/// 0 910 14
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(0, 9), Range(10, 14) });
assertEqual(cache.dumpQueue(), { Range(0, 9), Range(10, 14) });
2022-08-31 16:07:40 +00:00
ASSERT_EQ(cache.getFileSegmentsNum(), 2);
ASSERT_EQ(cache.getUsedCacheSize(), 15);
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 3\n";
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
/// Get [9, 9]
assertEqual(cache.getOrSet(key, 9, 1, {}), { Range(0, 9) }, { State::DOWNLOADED });
assertEqual(cache.dumpQueue(), { Range(10, 14), Range(0, 9) });
/// Get [9, 10]
assertEqual(cache.getOrSet(key, 9, 2, {}),
{ Range(0, 9), Range(10, 14) },
{ State::DOWNLOADED, State::DOWNLOADED });
/// Get [10, 10]
assertEqual(cache.getOrSet(key, 10, 1, {}), { Range(10, 14) }, { State::DOWNLOADED });
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(0, 9), Range(10, 14) });
assertEqual(cache.dumpQueue(), { Range(0, 9), Range(10, 14) });
ASSERT_EQ(cache.getFileSegmentsNum(), 2);
ASSERT_EQ(cache.getUsedCacheSize(), 15);
std::cerr << "Step 4\n";
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
download(cache.getOrSet(key, 17, 4, {})); /// Get [17, 20]
download(cache.getOrSet(key, 24, 3, {})); /// Get [24, 26]
download(cache.getOrSet(key, 27, 1, {})); /// Get [27, 27]
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [__________][_____] [____] [___][]
/// ^ ^^ ^ ^ ^ ^ ^^^
/// 0 910 14 17 20 24 2627
///
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(0, 9), Range(10, 14), Range(17, 20), Range(24, 26), Range(27, 27) });
assertEqual(cache.dumpQueue(), { Range(0, 9), Range(10, 14), Range(17, 20), Range(24, 26), Range(27, 27) });
ASSERT_EQ(cache.getFileSegmentsNum(), 5);
ASSERT_EQ(cache.getUsedCacheSize(), 23);
2023-01-05 20:32:40 +00:00
std::cerr << "Step 5\n";
2022-08-31 16:07:40 +00:00
{
2022-09-06 11:30:02 +00:00
auto holder = cache.getOrSet(key, 0, 26, {}); /// Get [0, 25]
2023-01-05 20:32:40 +00:00
assertEqual(holder,
{ Range(0, 9), Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 23), Range(24, 26) },
{ State::DOWNLOADED, State::DOWNLOADED, State::EMPTY, State::DOWNLOADED, State::EMPTY, State::DOWNLOADED });
download(get(holder, 2)); /// [27, 27] was evicted.
assertEqual(holder,
{ Range(0, 9), Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 23), Range(24, 26) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::EMPTY, State::DOWNLOADED });
assertDownloadFails(get(holder, 4));
assertEqual(holder,
{ Range(0, 9), Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 23), Range(24, 26) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::SKIP_CACHE, State::DOWNLOADED });
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Range [27, 27] must be evicted in previous getOrSet [0, 25].
/// Let's not invalidate pointers to returned segments from range [0, 25] and
/// as max elements size is reached, next attempt to put something in cache should fail.
/// This will also check that [27, 27] was indeed evicted.
2023-01-05 20:32:40 +00:00
auto holder2 = cache.getOrSet(key, 27, 1, {});
assertEqual(holder2, { Range(27, 27) }, { State::EMPTY });
assertDownloadFails(holder2->front());
assertEqual(holder2, { Range(27, 27) }, { State::SKIP_CACHE });
auto holder3 = cache.getOrSet(key, 28, 3, {});
assertEqual(holder3, { Range(28, 30) }, { State::EMPTY });
assertDownloadFails(holder3->front());
assertEqual(holder3, { Range(28, 30) }, { State::SKIP_CACHE });
2022-08-31 16:07:40 +00:00
}
2023-01-05 20:32:40 +00:00
/// Current cache: [__________][_____][ ][____] [___]
/// ^ ^ ^
/// 0 20 24
///
assertEqual(cache.getSnapshot(key), { Range(0, 9), Range(10, 14), Range(15, 16), Range(17, 20), Range(24, 26) });
assertEqual(cache.dumpQueue(), { Range(0, 9), Range(10, 14), Range(15, 16), Range(17, 20), Range(24, 26) });
ASSERT_EQ(cache.getFileSegmentsNum(), 5);
ASSERT_EQ(cache.getUsedCacheSize(), 24);
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 6\n";
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
{
auto holder = cache.getOrSet(key, 12, 10, {}); /// Get [12, 21]
assertEqual(holder,
{ Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 21) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::EMPTY });
download(get(holder, 3));
assertEqual(holder,
{ Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 21) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED });
2022-08-31 16:07:40 +00:00
}
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [_____][__][____][_] [___]
/// ^ ^ ^ ^ ^
/// 10 17 21 24 26
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 21), Range(24, 26) });
assertEqual(cache.dumpQueue(), { Range(24, 26), Range(10, 14), Range(15, 16), Range(17, 20), Range(21, 21) });
2022-08-31 16:07:40 +00:00
ASSERT_EQ(cache.getFileSegmentsNum(), 5);
2023-01-05 20:32:40 +00:00
ASSERT_EQ(cache.getUsedCacheSize(), 15);
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 7\n";
2022-08-31 16:07:40 +00:00
{
2023-01-05 20:32:40 +00:00
auto holder = cache.getOrSet(key, 23, 5, {}); /// Get [23, 27]
assertEqual(holder,
{ Range(23, 23), Range(24, 26), Range(27, 27) },
{ State::EMPTY, State::DOWNLOADED, State::EMPTY });
download(get(holder, 0));
download(get(holder, 2));
2022-08-31 16:07:40 +00:00
}
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [____][_] [][___][__]
/// ^ ^ ^^^ ^^ ^
/// 17 21 2324 26 27
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(17, 20), Range(21, 21), Range(23, 23), Range(24, 26), Range(27, 27) });
assertEqual(cache.dumpQueue(), { Range(17, 20), Range(21, 21), Range(23, 23), Range(24, 26), Range(27, 27) });
ASSERT_EQ(cache.getFileSegmentsNum(), 5);
2023-01-05 20:32:40 +00:00
ASSERT_EQ(cache.getUsedCacheSize(), 10);
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 8\n";
2022-08-31 16:07:40 +00:00
{
2022-09-06 11:30:02 +00:00
auto holder = cache.getOrSet(key, 2, 3, {}); /// Get [2, 4]
2023-01-05 20:32:40 +00:00
assertEqual(holder, { Range(2, 4) }, { State::EMPTY });
auto holder2 = cache.getOrSet(key, 30, 2, {}); /// Get [30, 31]
assertEqual(holder2, { Range(30, 31) }, { State::EMPTY });
download(get(holder, 0));
download(get(holder2, 0));
auto holder3 = cache.getOrSet(key, 23, 1, {}); /// Get [23, 23]
assertEqual(holder3, { Range(23, 23) }, { State::DOWNLOADED });
auto holder4 = cache.getOrSet(key, 24, 3, {}); /// Get [24, 26]
assertEqual(holder4, { Range(24, 26) }, { State::DOWNLOADED });
auto holder5 = cache.getOrSet(key, 27, 1, {}); /// Get [27, 27]
assertEqual(holder5, { Range(27, 27) }, { State::DOWNLOADED });
auto holder6 = cache.getOrSet(key, 0, 40, {});
assertEqual(holder6,
{ Range(0, 1), Range(2, 4), Range(5, 22), Range(23, 23), Range(24, 26), Range(27, 27), Range(28, 29), Range(30, 31), Range(32, 39) },
{ State::EMPTY, State::DOWNLOADED, State::EMPTY, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::EMPTY, State::DOWNLOADED, State::EMPTY });
assertDownloadFails(get(holder6, 0));
assertDownloadFails(get(holder6, 2));
assertDownloadFails(get(holder6, 6));
assertDownloadFails(get(holder6, 8));
2022-08-31 16:07:40 +00:00
}
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
/// Current cache: [___] [_][___][_] [__]
/// ^ ^ ^ ^ ^ ^ ^ ^
/// 2 4 23 24 26 27 30 31
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(2, 4), Range(23, 23), Range(24, 26), Range(27, 27), Range(30, 31) });
assertEqual(cache.dumpQueue(), { Range(27, 27), Range(24, 26), Range(23, 23), Range(30, 31), Range(2, 4) });
std::cerr << "Step 9\n";
/// Get [2, 4]
assertEqual(cache.getOrSet(key, 2, 3, {}), { Range(2, 4) }, { State::DOWNLOADED });
2022-01-13 11:57:56 +00:00
{
2022-09-06 11:30:02 +00:00
auto holder = cache.getOrSet(key, 25, 5, {}); /// Get [25, 29]
2023-01-05 20:32:40 +00:00
assertEqual(holder,
{ Range(24, 26), Range(27, 27), Range(28, 29) },
{ State::DOWNLOADED, State::DOWNLOADED, State::EMPTY });
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
auto & file_segment = get(holder, 2);
ASSERT_TRUE(file_segment.getOrSetDownloader() == FileSegment::getCallerId());
ASSERT_TRUE(file_segment.state() == State::DOWNLOADING);
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
bool lets_start_download = false;
std::mutex mutex;
std::condition_variable cv;
std::thread other_1([&]
2022-01-13 11:57:56 +00:00
{
2022-08-31 16:07:40 +00:00
DB::ThreadStatus thread_status_1;
auto query_context_1 = DB::Context::createCopy(getContext().context);
query_context_1->makeQueryContext();
query_context_1->setCurrentQueryId("query_id_1");
DB::CurrentThread::QueryScope query_scope_holder_1(query_context_1);
thread_status_1.attachQueryContext(query_context_1);
2023-01-05 20:32:40 +00:00
auto holder2 = cache.getOrSet(key, 25, 5, {}); /// Get [25, 29] once again.
assertEqual(holder2,
{ Range(24, 26), Range(27, 27), Range(28, 29) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADING });
2022-08-31 16:07:40 +00:00
2023-01-05 20:32:40 +00:00
auto & file_segment2 = get(holder2, 2);
ASSERT_TRUE(file_segment2.getOrSetDownloader() != FileSegment::getCallerId());
2022-08-31 16:07:40 +00:00
{
std::lock_guard lock(mutex);
lets_start_download = true;
}
cv.notify_one();
2023-01-05 20:32:40 +00:00
file_segment2.wait();
ASSERT_TRUE(file_segment2.state() == State::DOWNLOADED);
2022-08-31 16:07:40 +00:00
});
{
std::unique_lock lock(mutex);
cv.wait(lock, [&]{ return lets_start_download; });
2022-01-13 11:57:56 +00:00
}
2023-01-05 20:32:40 +00:00
download(file_segment);
ASSERT_TRUE(file_segment.state() == State::DOWNLOADED);
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
other_1.join();
2022-01-13 11:57:56 +00:00
}
2022-08-31 16:07:40 +00:00
/// Current cache: [___] [___][_][__][__]
/// ^ ^ ^ ^ ^^ ^^ ^
/// 2 4 24 26 27 2930 31
2023-01-05 20:32:40 +00:00
assertEqual(cache.getSnapshot(key), { Range(2, 4), Range(24, 26), Range(27, 27), Range(28, 29), Range(30, 31) });
assertEqual(cache.dumpQueue(), { Range(30, 31), Range(2, 4), Range(24, 26), Range(27, 27), Range(28, 29) });
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 10\n";
2022-08-31 16:07:40 +00:00
{
/// Now let's check the similar case but getting ERROR state after segment->wait(), when
2022-09-06 11:30:02 +00:00
/// state is changed not manually via segment->completeWithState(state) but from destructor of holder
2022-08-31 16:07:40 +00:00
/// and notify_all() is also called from destructor of holder.
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
auto holder = cache.getOrSet(key, 3, 23, {}); /// Get [3, 25]
assertEqual(holder,
{ Range(2, 4), Range(5, 23), Range(24, 26) },
{ State::DOWNLOADED, State::EMPTY, State::DOWNLOADED });
2022-01-21 15:39:34 +00:00
2023-01-05 20:32:40 +00:00
auto & file_segment = get(holder, 1);
ASSERT_TRUE(file_segment.getOrSetDownloader() == FileSegment::getCallerId());
ASSERT_TRUE(file_segment.state() == State::DOWNLOADING);
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
bool lets_start_download = false;
std::mutex mutex;
std::condition_variable cv;
2022-01-13 11:57:56 +00:00
2022-08-31 16:07:40 +00:00
std::thread other_1([&]
{
DB::ThreadStatus thread_status_1;
auto query_context_1 = DB::Context::createCopy(getContext().context);
query_context_1->makeQueryContext();
query_context_1->setCurrentQueryId("query_id_1");
DB::CurrentThread::QueryScope query_scope_holder_1(query_context_1);
thread_status_1.attachQueryContext(query_context_1);
2023-01-05 20:32:40 +00:00
auto holder2 = cache.getOrSet(key, 3, 23, {}); /// Get [3, 25] once again
assertEqual(holder,
{ Range(2, 4), Range(5, 23), Range(24, 26) },
{ State::DOWNLOADED, State::DOWNLOADING, State::DOWNLOADED });
2022-08-31 16:07:40 +00:00
2023-01-05 20:32:40 +00:00
auto & file_segment2 = get(holder, 1);
ASSERT_TRUE(file_segment2.getDownloader() != FileSegment::getCallerId());
2022-08-31 16:07:40 +00:00
{
std::lock_guard lock(mutex);
lets_start_download = true;
}
cv.notify_one();
2023-01-05 20:32:40 +00:00
file_segment2.wait();
ASSERT_TRUE(file_segment2.state() == DB::FileSegment::State::PARTIALLY_DOWNLOADED);
ASSERT_TRUE(file_segment2.getOrSetDownloader() == DB::FileSegment::getCallerId());
download(file_segment2);
2022-08-31 16:07:40 +00:00
});
2022-01-13 11:57:56 +00:00
{
2022-08-31 16:07:40 +00:00
std::unique_lock lock(mutex);
cv.wait(lock, [&]{ return lets_start_download; });
2022-01-13 11:57:56 +00:00
}
2022-08-31 16:07:40 +00:00
holder.reset();
other_1.join();
2023-01-05 20:32:40 +00:00
ASSERT_TRUE(file_segment.state() == DB::FileSegment::State::DOWNLOADED);
2022-01-13 11:57:56 +00:00
}
}
2022-01-21 15:39:34 +00:00
/// Current cache: [___][ ][___][_][__]
/// ^ ^^ ^ ^^ ^ ^
/// 2 45 24 2627 28 29
2022-01-13 11:57:56 +00:00
2023-01-05 20:32:40 +00:00
std::cerr << "Step 11\n";
2022-01-13 11:57:56 +00:00
{
/// Test LRUCache::restore().
auto cache2 = DB::FileCache(cache_base_path, settings);
2022-03-02 13:17:19 +00:00
cache2.initialize();
auto key = cache2.createKeyForPath("key1");
2022-03-09 09:36:52 +00:00
2023-01-05 20:32:40 +00:00
/// Get [2, 29]
assertEqual(cache2.getOrSet(key, 2, 28, {}),
{ Range(2, 4), Range(5, 23), Range(24, 26), Range(27, 27), Range(28, 29) },
{ State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED, State::DOWNLOADED });
2022-01-13 11:57:56 +00:00
}
2023-01-05 20:32:40 +00:00
std::cerr << "Step 12\n";
{
/// Test max file segment size
2022-03-25 17:31:15 +00:00
auto settings2 = settings;
2022-03-29 17:57:55 +00:00
settings2.max_file_segment_size = 10;
auto cache2 = DB::FileCache(caches_dir / "cache2", settings2);
2022-03-09 09:36:52 +00:00
cache2.initialize();
auto key = cache2.createKeyForPath("key1");
2022-03-09 09:36:52 +00:00
2023-01-05 20:32:40 +00:00
/// Get [0, 24]
assertEqual(cache2.getOrSet(key, 0, 25, {}),
{ Range(0, 9), Range(10, 19), Range(20, 24) },
{ State::EMPTY, State::EMPTY, State::EMPTY });
}
2022-06-05 16:00:59 +00:00
2022-01-13 11:57:56 +00:00
}
2022-12-06 10:04:15 +00:00
2022-12-06 17:27:05 +00:00
TEST_F(FileCacheTest, writeBuffer)
2022-12-06 10:04:15 +00:00
{
2023-01-05 20:32:40 +00:00
FileCacheSettings settings;
2022-12-06 17:27:05 +00:00
settings.max_size = 100;
2022-12-06 10:04:15 +00:00
settings.max_elements = 5;
2022-12-06 17:27:05 +00:00
settings.max_file_segment_size = 5;
2022-12-06 10:04:15 +00:00
2023-01-05 20:32:40 +00:00
FileCache cache(cache_base_path, settings);
2022-12-06 10:04:15 +00:00
cache.initialize();
2022-12-06 17:27:05 +00:00
auto write_to_cache = [&cache](const String & key, const Strings & data)
2022-12-06 10:04:15 +00:00
{
2022-12-06 17:27:05 +00:00
CreateFileSegmentSettings segment_settings;
segment_settings.kind = FileSegmentKind::Temporary;
segment_settings.unbounded = true;
2023-01-04 19:57:42 +00:00
auto holder = cache.set(cache.createKeyForPath(key), 0, 3, segment_settings);
EXPECT_EQ(holder->size(), 1);
auto & segment = holder->front();
WriteBufferToFileSegment out(&segment);
2022-12-06 17:27:05 +00:00
for (const auto & s : data)
out.write(s.data(), s.size());
return holder;
};
std::vector<fs::path> file_segment_paths;
{
auto holder = write_to_cache("key1", {"abc", "defg"});
2023-01-04 19:57:42 +00:00
file_segment_paths.emplace_back(holder->front().getPathInLocalCache());
2022-12-06 10:04:15 +00:00
2022-12-06 17:27:05 +00:00
ASSERT_EQ(fs::file_size(file_segment_paths.back()), 7);
2023-01-04 19:57:42 +00:00
ASSERT_TRUE(holder->front().range() == FileSegment::Range(0, 7));
2022-12-06 17:27:05 +00:00
ASSERT_EQ(cache.getUsedCacheSize(), 7);
2022-12-06 10:04:15 +00:00
2022-12-06 17:27:05 +00:00
{
auto holder2 = write_to_cache("key2", {"1", "22", "333", "4444", "55555"});
2023-01-04 19:57:42 +00:00
file_segment_paths.emplace_back(holder2->front().getPathInLocalCache());
2022-12-06 10:04:15 +00:00
2022-12-06 17:27:05 +00:00
ASSERT_EQ(fs::file_size(file_segment_paths.back()), 15);
2023-01-04 19:57:42 +00:00
ASSERT_TRUE(holder2->front().range() == FileSegment::Range(0, 15));
2022-12-06 17:27:05 +00:00
ASSERT_EQ(cache.getUsedCacheSize(), 22);
}
ASSERT_FALSE(fs::exists(file_segment_paths.back()));
ASSERT_EQ(cache.getUsedCacheSize(), 7);
}
2022-12-06 10:04:15 +00:00
2022-12-06 17:27:05 +00:00
for (const auto & file_segment_path : file_segment_paths)
{
ASSERT_FALSE(fs::exists(file_segment_path));
}
ASSERT_EQ(cache.getUsedCacheSize(), 0);
2022-12-06 10:04:15 +00:00
}
2022-12-06 17:27:05 +00:00
2022-12-06 10:04:15 +00:00
static Block generateBlock(size_t size = 0)
{
Block block;
ColumnWithTypeAndName column;
column.name = "x";
column.type = std::make_shared<DataTypeUInt64>();
{
MutableColumnPtr mut_col = column.type->createColumn();
for (size_t i = 0; i < size; ++i)
mut_col->insert(i);
column.column = std::move(mut_col);
}
block.insert(column);
return block;
}
static size_t readAllTemporaryData(TemporaryFileStream & stream)
{
Block block;
size_t read_rows = 0;
do
{
block = stream.read();
read_rows += block.rows();
} while (block);
return read_rows;
}
TEST_F(FileCacheTest, temporaryData)
{
DB::FileCacheSettings settings;
2022-12-06 17:27:05 +00:00
settings.max_size = 10_KiB;
settings.max_file_segment_size = 1_KiB;
2022-12-06 10:04:15 +00:00
DB::FileCache file_cache(cache_base_path, settings);
file_cache.initialize();
auto tmp_data_scope = std::make_shared<TemporaryDataOnDiskScope>(nullptr, &file_cache, 0);
2023-01-04 19:57:42 +00:00
auto some_data_holder = file_cache.getOrSet(file_cache.createKeyForPath("some_data"), 0, 5_KiB, CreateFileSegmentSettings{});
2022-12-06 10:04:15 +00:00
{
2023-01-04 19:57:42 +00:00
ASSERT_EQ(some_data_holder->size(), 5);
for (auto & segment : *some_data_holder)
2022-12-06 10:04:15 +00:00
{
ASSERT_TRUE(segment->getOrSetDownloader() == DB::FileSegment::getCallerId());
ASSERT_TRUE(segment->reserve(segment->range().size()));
2023-01-05 20:32:40 +00:00
download(*segment);
2023-01-04 19:57:42 +00:00
segment->complete();
2022-12-06 10:04:15 +00:00
}
}
size_t size_used_before_temporary_data = file_cache.getUsedCacheSize();
size_t segments_used_before_temporary_data = file_cache.getFileSegmentsNum();
ASSERT_GT(size_used_before_temporary_data, 0);
ASSERT_GT(segments_used_before_temporary_data, 0);
size_t size_used_with_temporary_data;
size_t segments_used_with_temporary_data;
{
auto tmp_data = std::make_unique<TemporaryDataOnDisk>(tmp_data_scope);
auto & stream = tmp_data->createStream(generateBlock());
ASSERT_GT(stream.write(generateBlock(100)), 0);
2022-12-06 17:27:05 +00:00
ASSERT_GT(file_cache.getUsedCacheSize(), 0);
ASSERT_GT(file_cache.getFileSegmentsNum(), 0);
2022-12-06 10:04:15 +00:00
size_t used_size_before_attempt = file_cache.getUsedCacheSize();
/// data can't be evicted because it is still held by `some_data_holder`
2022-12-06 17:27:05 +00:00
ASSERT_THROW({
stream.write(generateBlock(2000));
stream.flush();
}, DB::Exception);
2022-12-06 10:04:15 +00:00
ASSERT_EQ(file_cache.getUsedCacheSize(), used_size_before_attempt);
2022-12-06 17:27:05 +00:00
}
{
auto tmp_data = std::make_unique<TemporaryDataOnDisk>(tmp_data_scope);
auto & stream = tmp_data->createStream(generateBlock());
ASSERT_GT(stream.write(generateBlock(100)), 0);
2022-12-06 10:04:15 +00:00
some_data_holder.reset();
2022-12-06 17:27:05 +00:00
stream.write(generateBlock(2000));
2022-12-06 10:04:15 +00:00
auto stat = stream.finishWriting();
2022-12-06 17:27:05 +00:00
ASSERT_TRUE(fs::exists(stream.getPath()));
ASSERT_GT(fs::file_size(stream.getPath()), 100);
ASSERT_EQ(stat.num_rows, 2100);
ASSERT_EQ(readAllTemporaryData(stream), 2100);
2022-12-06 10:04:15 +00:00
size_used_with_temporary_data = file_cache.getUsedCacheSize();
segments_used_with_temporary_data = file_cache.getFileSegmentsNum();
2022-12-06 17:27:05 +00:00
ASSERT_GT(size_used_with_temporary_data, 0);
ASSERT_GT(segments_used_with_temporary_data, 0);
2022-12-06 10:04:15 +00:00
}
/// All temp data should be evicted after removing temporary files
2022-12-06 17:27:05 +00:00
ASSERT_LE(file_cache.getUsedCacheSize(), size_used_with_temporary_data);
ASSERT_LE(file_cache.getFileSegmentsNum(), segments_used_with_temporary_data);
2022-12-06 10:04:15 +00:00
/// Some segments reserved by `some_data_holder` was eviced by temporary data
2022-12-06 17:27:05 +00:00
ASSERT_LE(file_cache.getUsedCacheSize(), size_used_before_temporary_data);
ASSERT_LE(file_cache.getFileSegmentsNum(), segments_used_before_temporary_data);
2022-12-06 10:04:15 +00:00
}