Skip to content

Commit 78a980f

Browse files
authored
feat(compaction): support lru cache (alibaba#210)
1 parent 2de5638 commit 78a980f

34 files changed

Lines changed: 1201 additions & 143 deletions

include/paimon/defs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,11 @@ struct PAIMON_EXPORT Options {
402402
/// you can add the conf like this: 'file.compression.per.level' = '0:lz4,1:zstd'.
403403
/// If a level is not configured, the default compression set by FILE_COMPRESSION will be used.
404404
static const char FILE_COMPRESSION_PER_LEVEL[];
405+
/// "lookup.cache-max-memory-size" - Max memory size for lookup cache. Default value is 256 mb.
406+
static const char LOOKUP_CACHE_MAX_MEMORY_SIZE[];
407+
/// "lookup.cache.high-priority-pool-ratio" - The fraction of cache memory that is reserved for
408+
/// high-priority data like index, filter. Default value is 0.25.
409+
static const char LOOKUP_CACHE_HIGH_PRIO_POOL_RATIO[];
405410
};
406411

407412
static constexpr int64_t BATCH_WRITE_COMMIT_IDENTIFIER = std::numeric_limits<int64_t>::max();

src/paimon/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ set(PAIMON_COMMON_SRCS
6464
common/io/data_output_stream.cpp
6565
common/io/memory_segment_output_stream.cpp
6666
common/io/offset_input_stream.cpp
67-
common/io/cache/cache.cpp
6867
common/io/cache/cache_key.cpp
6968
common/io/cache/cache_manager.cpp
69+
common/io/cache/lru_cache.cpp
7070
common/logging/logging.cpp
7171
common/lookup/sort/sort_lookup_store_factory.cpp
7272
common/lookup/lookup_store_factory.cpp
@@ -466,6 +466,7 @@ if(PAIMON_BUILD_TESTS)
466466
common/utils/roaring_bitmap64_test.cpp
467467
common/utils/range_helper_test.cpp
468468
common/utils/read_ahead_cache_test.cpp
469+
common/io/cache/lru_cache_test.cpp
469470
common/utils/byte_range_combiner_test.cpp
470471
common/utils/scope_guard_test.cpp
471472
common/utils/serialization_utils_test.cpp
@@ -495,6 +496,7 @@ if(PAIMON_BUILD_TESTS)
495496
SOURCES
496497
common/compression/block_compression_factory_test.cpp
497498
common/sst/sst_file_io_test.cpp
499+
common/sst/block_cache_test.cpp
498500
common/utils/crc32c_test.cpp
499501
STATIC_LINK_LIBS
500502
paimon_shared

src/paimon/common/defs.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,7 @@ const char Options::COMPACTION_FORCE_UP_LEVEL_0[] = "compaction.force-up-level-0
113113
const char Options::LOOKUP_WAIT[] = "lookup-wait";
114114
const char Options::LOOKUP_COMPACT[] = "lookup-compact";
115115
const char Options::LOOKUP_COMPACT_MAX_INTERVAL[] = "lookup-compact.max-interval";
116+
const char Options::LOOKUP_CACHE_MAX_MEMORY_SIZE[] = "lookup.cache-max-memory-size";
117+
const char Options::LOOKUP_CACHE_HIGH_PRIO_POOL_RATIO[] = "lookup.cache.high-priority-pool-ratio";
116118

117119
} // namespace paimon

src/paimon/common/io/cache/cache.cpp

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/paimon/common/io/cache/cache.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@
2525
#include "paimon/result.h"
2626

2727
namespace paimon {
28+
2829
class CacheValue;
2930

31+
/// Callback invoked when a cache entry is evicted by the LRU policy.
32+
using CacheCallback = std::function<void(const std::shared_ptr<CacheKey>&)>;
33+
3034
class Cache {
3135
public:
3236
virtual ~Cache() = default;
@@ -42,31 +46,27 @@ class Cache {
4246

4347
virtual void InvalidateAll() = 0;
4448

45-
virtual CacheKeyMap AsMap() = 0;
46-
};
47-
48-
class NoCache : public Cache {
49-
public:
50-
Result<std::shared_ptr<CacheValue>> Get(
51-
const std::shared_ptr<CacheKey>& key,
52-
std::function<Result<std::shared_ptr<CacheValue>>(const std::shared_ptr<CacheKey>&)>
53-
supplier) override;
54-
void Put(const std::shared_ptr<CacheKey>& key,
55-
const std::shared_ptr<CacheValue>& value) override;
56-
void Invalidate(const std::shared_ptr<CacheKey>& key) override;
57-
void InvalidateAll() override;
58-
CacheKeyMap AsMap() override;
49+
virtual size_t Size() const = 0;
5950
};
6051

6152
class CacheValue {
6253
public:
63-
explicit CacheValue(const MemorySegment& segment) : segment_(segment) {}
54+
CacheValue(const MemorySegment& segment, CacheCallback callback)
55+
: segment_(segment), callback_(std::move(callback)) {}
6456

6557
const MemorySegment& GetSegment() const {
6658
return segment_;
6759
}
6860

61+
/// Invoke the eviction callback, if one was registered.
62+
void OnEvict(const std::shared_ptr<CacheKey>& key) const {
63+
if (callback_) {
64+
callback_(key);
65+
}
66+
}
67+
6968
private:
7069
MemorySegment segment_;
70+
CacheCallback callback_;
7171
};
7272
} // namespace paimon

src/paimon/common/io/cache/cache_key.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ class CacheKey {
3333
virtual ~CacheKey() = default;
3434

3535
virtual bool IsIndex() const = 0;
36-
virtual size_t HashCode() const = 0;
36+
3737
virtual bool Equals(const CacheKey& other) const = 0;
38+
39+
virtual size_t HashCode() const = 0;
3840
};
3941

4042
class PositionCacheKey : public CacheKey {
@@ -76,7 +78,4 @@ struct CacheKeyEqual {
7678
}
7779
};
7880

79-
using CacheKeyMap = std::unordered_map<std::shared_ptr<CacheKey>, std::shared_ptr<CacheValue>,
80-
CacheKeyHash, CacheKeyEqual>;
81-
8281
} // namespace paimon

src/paimon/common/io/cache/cache_manager.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ namespace paimon {
2020

2121
Result<MemorySegment> CacheManager::GetPage(
2222
std::shared_ptr<CacheKey>& key,
23-
std::function<Result<MemorySegment>(const std::shared_ptr<CacheKey>&)> reader) {
23+
std::function<Result<MemorySegment>(const std::shared_ptr<CacheKey>&)> reader,
24+
CacheCallback eviction_callback) {
2425
auto& cache = key->IsIndex() ? index_cache_ : data_cache_;
25-
auto supplier = [&](const std::shared_ptr<CacheKey>& k) -> Result<std::shared_ptr<CacheValue>> {
26-
PAIMON_ASSIGN_OR_RAISE(MemorySegment segment, reader(k));
27-
return std::make_shared<CacheValue>(segment);
26+
auto supplier =
27+
[&](const std::shared_ptr<CacheKey>& key) -> Result<std::shared_ptr<CacheValue>> {
28+
PAIMON_ASSIGN_OR_RAISE(MemorySegment segment, reader(key));
29+
return std::make_shared<CacheValue>(segment, std::move(eviction_callback));
2830
};
2931
PAIMON_ASSIGN_OR_RAISE(std::shared_ptr<CacheValue> cache_value, cache->Get(key, supplier));
3032
return cache_value->GetSegment();

src/paimon/common/io/cache/cache_manager.h

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,67 @@
2222

2323
#include "paimon/common/io/cache/cache.h"
2424
#include "paimon/common/io/cache/cache_key.h"
25+
#include "paimon/common/io/cache/lru_cache.h"
2526
#include "paimon/common/memory/memory_segment.h"
2627
#include "paimon/result.h"
2728

2829
namespace paimon {
2930
class CacheManager {
3031
public:
31-
CacheManager() {
32-
// todo implements cache
33-
data_cache_ = std::make_shared<NoCache>();
34-
index_cache_ = std::make_shared<NoCache>();
32+
/// Refreshing the cache comes with some costs, so not every time we visit the CacheManager, but
33+
/// every 10 visits, refresh the LRU strategy.
34+
static constexpr int32_t REFRESH_COUNT = 10;
35+
36+
/// Container that wraps a MemorySegment with an access counter for refresh.
37+
class SegmentContainer {
38+
public:
39+
explicit SegmentContainer(const MemorySegment& segment) : segment_(segment) {}
40+
41+
const MemorySegment& Access() {
42+
access_count_++;
43+
return segment_;
44+
}
45+
46+
int32_t GetAccessCount() const {
47+
return access_count_;
48+
}
49+
50+
private:
51+
MemorySegment segment_;
52+
int32_t access_count_ = 0;
53+
};
54+
55+
/// Constructs a CacheManager with LRU caching.
56+
/// @param max_memory_bytes Total cache capacity in bytes.
57+
/// @param high_priority_pool_ratio Ratio of capacity reserved for index cache [0.0, 1.0).
58+
/// If 0, index and data share the same cache.
59+
CacheManager(int64_t max_memory_bytes, double high_priority_pool_ratio) {
60+
auto index_cache_bytes = static_cast<int64_t>(max_memory_bytes * high_priority_pool_ratio);
61+
auto data_cache_bytes =
62+
static_cast<int64_t>(max_memory_bytes * (1.0 - high_priority_pool_ratio));
63+
data_cache_ = std::make_shared<LruCache>(data_cache_bytes);
64+
if (high_priority_pool_ratio == 0.0) {
65+
index_cache_ = data_cache_;
66+
} else {
67+
index_cache_ = std::make_shared<LruCache>(index_cache_bytes);
68+
}
3569
}
3670

3771
Result<MemorySegment> GetPage(
3872
std::shared_ptr<CacheKey>& key,
39-
std::function<Result<MemorySegment>(const std::shared_ptr<CacheKey>&)> reader);
73+
std::function<Result<MemorySegment>(const std::shared_ptr<CacheKey>&)> reader,
74+
CacheCallback eviction_callback);
4075

4176
void InvalidPage(const std::shared_ptr<CacheKey>& key);
4277

78+
const std::shared_ptr<Cache>& DataCache() const {
79+
return data_cache_;
80+
}
81+
82+
const std::shared_ptr<Cache>& IndexCache() const {
83+
return index_cache_;
84+
}
85+
4386
private:
4487
std::shared_ptr<Cache> data_cache_;
4588
std::shared_ptr<Cache> index_cache_;

0 commit comments

Comments
 (0)