chore: initial commit
Some checks failed
Code Analysis / analysis (push) Failing after 2m59s

This commit is contained in:
2025-12-30 22:34:58 +07:00
commit 35a6349071
63 changed files with 2675 additions and 0 deletions

118
rediska/cache/lru/LRU.cpp vendored Normal file
View File

@@ -0,0 +1,118 @@
#include "rediska/cache/lru/LRU.hpp"
#include <expected>
#include <mutex>
#include <optional>
#include <unordered_map>
#include "rediska/cache/lru/LRUConfig.hpp"
#include "rediska/cache/types.hpp"
#include "rediska/common/MessageArguments.hpp"
#include "rediska/common/types.hpp"
#include "rediska/common/utils.hpp"
namespace cache {
LRU::LRU(LRUConfig config, CacheOpCallback callback)
: config_(std::move(config)), callback_(callback) {}
void LRU::get(CacheKey&& key) {
std::shared_lock lock(mutex_);
auto it = keyToItem_.find(key);
if (it == keyToItem_.end()) {
return callback_(std::unexpected<RediskaReturnCode>(RediskaReturnCode::NOT_FOUND));
}
auto& metadata = it->second->location.metadata;
if (metadata.isExpired()) {
evict(it);
return callback_(std::unexpected<RediskaReturnCode>(RediskaReturnCode::KEY_EXPIRED));
}
if (config_.resetTTLOnAccess) metadata.resetExpirationTime();
// Move to start
lru_list_.splice(lru_list_.begin(), lru_list_, it->second);
keyToItem_[key] = lru_list_.begin();
callback_(std::make_optional(it->second->location.value));
}
void LRU::set(CacheKey&& key, CacheValue&& value, TTL ttl) {
std::unique_lock lock(mutex_);
auto it = keyToItem_.find(key);
if (it != keyToItem_.end()) {
it->second->location.value = std::move(value);
it->second->location.metadata.resetExpirationTime();
lru_list_.splice(lru_list_.begin(), lru_list_, it->second);
callback_(std::nullopt);
return;
}
if (isFull()) evict();
lru_list_.push_front(
CacheNode {
.key = std::move(key),
.location = ItemHandle{
.value = std::move(value),
.metadata = LRU::ItemMetadata(ttl)
}
}
);
keyToItem_[key] = lru_list_.begin();
callback_(std::nullopt);
}
void LRU::applyTo(CacheKey&& key, OperationId op, MessageArguments&& args) {
std::unique_lock lock(mutex_);
auto it = keyToItem_.find(key);
if (it == keyToItem_.end()) {
return callback_(std::unexpected<RediskaReturnCode>(RediskaReturnCode::NOT_FOUND));
}
auto& metadata = it->second->location.metadata;
std::expected<std::optional<CacheValue>, RediskaReturnCode> value;
std::visit([&value, op](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (is_any_of_v<T, int64_t, bool, double, std::string>) {
value = std::unexpected(RediskaReturnCode::INCOMPATIBLE_OPERATION);
} else if constexpr (std::is_same_v<T, std::shared_ptr<ListDataStructure>>) {
// TODO: Replace with real data argument
DSValue dummy_data{};
std::expected<std::optional<DSValue>, DSReturnCode> res = arg->handle(op, std::move(dummy_data));
if (!res) {
value = std::unexpected(DSReturnCodeToRediskaReturnCode(res.error()));
return;
}
if (!res.value().has_value()) {
value = std::nullopt;
return;
}
// TODO: Explore implicit conversion
// Attempts to covert failed
value = std::visit([](auto&& arg) -> CacheValue {
return CacheValue{arg};
}, std::move(res->value()));
}
}, it->second->location.value);
lru_list_.splice(lru_list_.begin(), lru_list_, it->second);
callback_(std::move(value));
return;
}
void LRU::evict() {
if (lru_list_.empty()) return;
keyToItem_.erase(lru_list_.back().key);
lru_list_.pop_back();
}
void LRU::evict(const std::unordered_map<CacheKey, std::list<CacheNode>::iterator>::iterator node) {
lru_list_.erase(node->second);
keyToItem_.erase(node);
}
inline bool LRU::isFull() const {
return lru_list_.size() >= config_.maxCapacity;
}
}