跳转至

4. RLruCache

使用下述功能需要包含头文件coke/rlru_cache.h

coke::RlruCache

RlruCache是一个类似RlruCache的并发安全的缓存容器,用于大量读取且极少写入的场景。该容器在需要淘汰一条数据时,不会从全局中进行选择,而是随机选择一些数据并淘汰其中上次使用时刻最久远的那条。

template<typename K, typename V, typename H = std::hash<K>,
         typename E = std::equal_to<>>
class RlruCache;

RlruCache使用哈希表管理数据,默认使用std::hash<K>计算key的哈希值,使用std::equal_to<void>比较两个key是否等价。

成员类型

using Key = K;
using Value = V;
using Hash = H;
using Equal = E;
using Entry = detail::RlruEntry<K, V>;
using Handle = detail::RlruHandle<K, V>;
using SizeType = std::size_t;

成员函数

  • 构造函数

    创建指定容量的RlruCache。若max_size为0则转换为SizeType(-1)

    当需要淘汰数据时,从至多max_scan个数据中进行选择。

    explicit RlruCache(SizeType max_size = 0, SizeType max_scan = 5,
                       const Hash &hash = Hash(), const Equal &equal = Equal());
    

    RlruCache不可移动、不可复制。

    RlruCache(RlruCache &&) = delete;
    RlruCache &operator=(RlruCache &&) = delete;
    
    RlruCache(const RlruCache &) = delete;
    RlruCache &operator=(const RlruCache &) = delete;
    
  • 析构函数

    销毁RlruCache,应保证所有通过get_or_create返回的handle都不再处于等待状态。

    ~RlruCache();
    
  • 容量查询

    // 获取当前缓存的条目数
    SizeType size() const;
    
    // 获取构造时传入的缓存容量
    SizeType capacity() const;
    
  • 获取条目

    通过键查找条目,返回空handle表示未命中。命中时会自动将key升热。

    template<typename U>
        requires HashEqualComparable<Hash, Equal, Key, U>
    Handle get(const U &key);
    
  • 获取或创建条目

    返回(handle, created)对。当createdtrue时,调用者应负责填充值并唤醒等待者。

    template<typename U>
        requires (HashEqualComparable<Hash, Equal, Key, U> &&
                  std::constructible_from<Key, const U &>)
    [[nodiscard]]
    std::pair<Handle, bool> get_or_create(const U &key);
    
  • 插入条目

    直接插入条目,使用args...构造value,并返回对应handle。若key存在则会被覆盖,此前已经获取的与旧值关联的handle仍能访问旧的值。

    template<typename U, typename... Args>
        requires (HashEqualComparable<Hash, Equal, Key, const U &> &&
                  std::constructible_from<Key, const U &> &&
                  std::constructible_from<Value, Args && ...>)
    Handle put(const U &key, Args &&...args);
    
  • 删除条目

    支持通过键或handle删除。条目会立即被移除,但此前已经获取的handle仍可使用。

    template<typename U>
        requires HashEqualComparable<Hash, Equal, Key, const U &>
    void remove(const U &key);
    
    void remove(const Handle &handle);
    
  • 清空缓存

    void clear();
    

coke::detail::RlruHandle

  • 构造、赋值、析构函数

    // 创建一个空RlruHandle,不关联任何条目。
    RlruHandle() noexcept;
    
    // 复制构造,创建一个新的RlruHandle,关联同一个条目。
    RlruHandle(const RlruHandle &) noexcept;
    
    // 移动构造
    RlruHandle(RlruHandle &&) noexcept;
    
    // 复制赋值,关联同一个条目。
    RlruHandle &operator=(const RlruHandle &) noexcept;
    
    // 移动赋值
    RlruHandle &operator=(RlruHandle &&) noexcept;
    
    // 析构函数,自动释放关联的条目。
    ~RlruHandle();
    
  • 状态检查

    // 是否关联条目
    operator bool() const noexcept;
    
    // 是否正在等待值
    bool waiting() const noexcept;
    
    // 是否成功设置值
    bool success() const noexcept;
    
    // 是否标记为失败
    bool failed() const noexcept;
    
  • 值操作

    填充值或标记失败状态后,均需要调用notify_one/notify_all唤醒等待者。

    // 原地构造值
    template<typename... Args>
    void emplace_value(Args &&...args)
    
    // 通过回调函数设置值
    template<typename ValueCreater>
    void create_value(ValueCreater &&creater)
    
    // 标记为失败状态
    void set_failed();
    
  • 异步等待

    协程返回一个int类型整数,有以下几种情况

    • coke::TOP_SUCCESS表示成功取出
    • coke::TOP_TIMEOUT表示等待超时,wait_for可能返回该值
    • coke::TOP_ABORTED表示进程正在退出
    • coke::TOP_CLOSED表示容器为空且已被关闭
    • 负数表示发生系统错误,该情况几乎不会发生
    // 等待至状态变化
    Task<int> wait();
    
    // 带超时的等待
    Task<int> wait_for(coke::NanoSec nsec);
    
  • 唤醒机制

    // 唤醒单个等待协程
    void notify_one();
    
    // 唤醒所有等待协程
    void notify_all();
    
  • 获取值

    // 获取key
    const Key &key() const noexcept;
    
    // 获取value,要求此时处于成功状态
    const Value &value() const noexcept;
    
    // 获取可修改的value,要求此时处于成功状态。使用者保证后续对value的修改是线程安全的。
    Value &mutable_value() noexcept;
    

示例

该容器使用方式与LruCache一致,可参考example/ex018-lru_cache.cpp