#pragma once #include #include #include #include #include #include "KICachePolicy.h" namespace KamaCache { // 前向声明 template class KLruCache; template class LruNode { private: Key key_; Value value_; size_t accessCount_; // 访问次数 std::weak_ptr> prev_; // 改为weak_ptr打破循环引用 std::shared_ptr> next_; public: LruNode(Key key, Value value) : key_(key) , value_(value) , accessCount_(1) {} // 提供必要的访问器 Key getKey() const { return key_; } Value getValue() const { return value_; } void setValue(const Value& value) { value_ = value; } size_t getAccessCount() const { return accessCount_; } void incrementAccessCount() { ++accessCount_; } friend class KLruCache; }; template class KLruCache : public KICachePolicy { public: using LruNodeType = LruNode; using NodePtr = std::shared_ptr; using NodeMap = std::unordered_map; KLruCache(int capacity) : capacity_(capacity) { initializeList(); } ~KLruCache() override = default; // 添加缓存 void put(Key key, Value value) override { if (capacity_ <= 0) return; std::lock_guard lock(mutex_); auto it = nodeMap_.find(key); if (it != nodeMap_.end()) { // 如果在当前容器中,则更新value,并调用get方法,代表该数据刚被访问 updateExistingNode(it->second, value); return ; } addNewNode(key, value); } bool get(Key key, Value& value) override { std::lock_guard lock(mutex_); auto it = nodeMap_.find(key); if (it != nodeMap_.end()) { moveToMostRecent(it->second); value = it->second->getValue(); return true; } return false; } Value get(Key key) override { Value value{}; // memset(&value, 0, sizeof(value)); // memset 是按字节设置内存的,对于复杂类型(如 string)使用 memset 可能会破坏对象的内部结构 get(key, value); return value; } // 删除指定元素 void remove(Key key) { std::lock_guard lock(mutex_); auto it = nodeMap_.find(key); if (it != nodeMap_.end()) { removeNode(it->second); nodeMap_.erase(it); } } private: void initializeList() { // 创建首尾虚拟节点 dummyHead_ = std::make_shared(Key(), Value()); dummyTail_ = std::make_shared(Key(), Value()); dummyHead_->next_ = dummyTail_; dummyTail_->prev_ = dummyHead_; } void updateExistingNode(NodePtr node, const Value& value) { node->setValue(value); moveToMostRecent(node); } void addNewNode(const Key& key, const Value& value) { if (nodeMap_.size() >= capacity_) { evictLeastRecent(); } NodePtr newNode = std::make_shared(key, value); insertNode(newNode); nodeMap_[key] = newNode; } // 将该节点移动到最新的位置 void moveToMostRecent(NodePtr node) { removeNode(node); insertNode(node); } void removeNode(NodePtr node) { if(!node->prev_.expired() && node->next_) { auto prev = node->prev_.lock(); // 使用lock()获取shared_ptr prev->next_ = node->next_; node->next_->prev_ = prev; node->next_ = nullptr; // 清空next_指针,彻底断开节点与链表的连接 } } // 从尾部插入结点 void insertNode(NodePtr node) { node->next_ = dummyTail_; node->prev_ = dummyTail_->prev_; dummyTail_->prev_.lock()->next_ = node; // 使用lock()获取shared_ptr dummyTail_->prev_ = node; } // 驱逐最近最少访问 void evictLeastRecent() { NodePtr leastRecent = dummyHead_->next_; removeNode(leastRecent); nodeMap_.erase(leastRecent->getKey()); } private: int capacity_; // 缓存容量 NodeMap nodeMap_; // key -> Node std::mutex mutex_; NodePtr dummyHead_; // 虚拟头结点 NodePtr dummyTail_; }; // LRU优化:Lru-k版本。 通过继承的方式进行再优化 template class KLruKCache : public KLruCache { public: KLruKCache(int capacity, int historyCapacity, int k) : KLruCache(capacity) // 调用基类构造 , historyList_(std::make_unique>(historyCapacity)) , k_(k) {} Value get(Key key) { // 首先尝试从主缓存获取数据 Value value{}; bool inMainCache = KLruCache::get(key, value); // 获取并更新访问历史计数 size_t historyCount = historyList_->get(key); historyCount++; historyList_->put(key, historyCount); // 如果数据在主缓存中,直接返回 if (inMainCache) { return value; } // 如果数据不在主缓存,但访问次数达到了k次 if (historyCount >= k_) { // 检查是否有历史值记录 auto it = historyValueMap_.find(key); if (it != historyValueMap_.end()) { // 有历史值,将其添加到主缓存 Value storedValue = it->second; // 从历史记录移除 historyList_->remove(key); historyValueMap_.erase(it); // 添加到主缓存 KLruCache::put(key, storedValue); return storedValue; } // 没有历史值记录,无法添加到缓存,返回默认值 } // 数据不在主缓存且不满足添加条件,返回默认值 return value; } void put(Key key, Value value) { // 检查是否已在主缓存 Value existingValue{}; bool inMainCache = KLruCache::get(key, existingValue); if (inMainCache) { // 已在主缓存,直接更新 KLruCache::put(key, value); return; } // 获取并更新访问历史 size_t historyCount = historyList_->get(key); historyCount++; historyList_->put(key, historyCount); // 保存值到历史记录映射,供后续get操作使用 historyValueMap_[key] = value; // 检查是否达到k次访问阈值 if (historyCount >= k_) { // 达到阈值,添加到主缓存 historyList_->remove(key); historyValueMap_.erase(key); KLruCache::put(key, value); } } private: int k_; // 进入缓存队列的评判标准 std::unique_ptr> historyList_; // 访问数据历史记录(value为访问次数) std::unordered_map historyValueMap_; // 存储未达到k次访问的数据值 }; // lru优化:对lru进行分片,提高高并发使用的性能 template class KHashLruCaches { public: KHashLruCaches(size_t capacity, int sliceNum) : capacity_(capacity) , sliceNum_(sliceNum > 0 ? sliceNum : std::thread::hardware_concurrency()) { size_t sliceSize = std::ceil(capacity / static_cast(sliceNum_)); // 获取每个分片的大小 for (int i = 0; i < sliceNum_; ++i) { lruSliceCaches_.emplace_back(new KLruCache(sliceSize)); } } void put(Key key, Value value) { // 获取key的hash值,并计算出对应的分片索引 size_t sliceIndex = Hash(key) % sliceNum_; lruSliceCaches_[sliceIndex]->put(key, value); } bool get(Key key, Value& value) { // 获取key的hash值,并计算出对应的分片索引 size_t sliceIndex = Hash(key) % sliceNum_; return lruSliceCaches_[sliceIndex]->get(key, value); } Value get(Key key) { Value value; memset(&value, 0, sizeof(value)); get(key, value); return value; } private: // 将key转换为对应hash值 size_t Hash(Key key) { std::hash hashFunc; return hashFunc(key); } private: size_t capacity_; // 总容量 int sliceNum_; // 切片数量 std::vector>> lruSliceCaches_; // 切片LRU缓存 }; } // namespace KamaCache