目录

LRUHandle

LRUCache

LRUCacheShard

关于LRUCacheShard不同优先级链表的实现

整体说来,rocksdb对于LRUCache的实现还是比较简单的,和我们平时见到的LRUCache基本一致,核心数据结构包括一个hashtable,用于存放cache所管理的数据,另一个数据结构为一个由双向循环链表实现的LRUList, 用于提供LRU语义。除了LRUCache以外,rocksdb还提供了另外几种Cache实现,LRUCache在rocksdb的Cache继承体系如下所示:

LRUHandle

LRUHandle是LRUCache存储的最基本元素。该对象用于封装上层调用者传来的value和key,另外需要注意的是被LRUCache管理的数据都应该在堆上分配。LRUHandle的关键数据如下:

struct LRUHandle {/* 实际的value */void* value;/* 析构函数 */void (*deleter)(const Slice&, void* value);/* 用于hashtable,拉链法的下一个元素 */LRUHandle* next_hash;/* 用于LRU链表 */LRUHandle* next;LRUHandle* prev;size_t charge;size_t key_length;uint32_t refs;     // a number of refs to this entry// cache itself is counted as 1/** 记录了该Handle是否在cache中。* 该Handle是否为高优先级Handle,由调用者插数据时指定。* 是否位于高优先级队列中,如果该handle为高优先级Handle,则会将其插入LRU链表。*/char flags;uint32_t hash;     // Hash of key(); used for fast sharding and comparisons/* 真正的key数据: key_data[0] -- key_data(key_length) */char key_data[1];  // Beginning of key
}

LRUHandle共有三种状态:

  • 被外部引用并且在LRUCache的hashtable中, 需要注意的是如果一个Handle被外部引用,那么rocksdb就不会将该元素放在LRU链表中。此时Handle的引用计数应该大于1,并且in_cache == true。
  • 没有被外部引用,此时该Handle会被LRU链表管理,在内存不足时可以释放掉。此时Handle的引用计数等于1,并且in_cache == true。
  • 被外部引用,但是不在cache中,此时Handle的引用计数大于0,并且in_cache == false。

状态转换流程如下:

  • 当想LRUCache中插入Handle时,此时Handle的状态为state1
  • 在state1的基础上,对一个Handle执行Release操作,该Handle的状态将为state2
  • 在state1的基础上,对一个Handle执行Erase操作,该Handle的状态将为state3
  • 在state2的基础上,如果caller查到到一个Handle,此时状态将为state1

另外需要注意的是,对于rocksdb的LRUCache的实现,Handle在hashtable中不一定在LRU链表中,但是Handle在LRU链表中,一定在hashtable中。

LRUCache

整体上管理LRUCache的类。为了减少锁冲突,rockdb将一个LRUCache分割成一系列小的LRUCache分片,每一个LRUCache分片用LRUCacheShard对象表示。所以LRUCache类拥有一个LRUCacheShared列表。整体说来LRUCache并没有对于LRU-Cache管理的核心逻辑,类接口都是一些辅助函数,其类定义如下:

class LRUCache : public ShardedCache {public:// 构造函数会根据num_shard_bits创建一系列LRUCacheShard对象LRUCache(size_t capacity, int num_shard_bits, bool strict_capacity_limit,double high_pri_pool_ratio);virtual ~LRUCache();virtual const char* Name() const override { return "LRUCache"; }virtual CacheShard* GetShard(int shard) override;virtual const CacheShard* GetShard(int shard) const override;virtual void* Value(Handle* handle) override;virtual size_t GetCharge(Handle* handle) const override;virtual uint32_t GetHash(Handle* handle) const override;virtual void DisownData() override;private:LRUCacheShard* shards_;
};

LRUCacheShard

LRUCacheShard代表一个LRU-Cache的分片,该类实现了LRU-Cache的核心语义。首先需要确定一点,LRUCacheShard管理的所有数据都被存放在了一个hashtable中,该类为LRUHandleTable。LRUHandleTable是rocksdb自己实现的hashtable类,其提供的语义与常见的hashtable的语义相同,但是该类具有比系统类库更好的性能。另外,LRUCacheShard还持有一个双向循环链表,用于实现LRU语义。
一般来说,如果一个数据空间加入到LRUCache后,该数据空间不但被hashtable引用,还会被LRU链表引用。但是rocksdb实现的LRUCache语义与常见的LRUCache有一点不同:

  • hashtable持有LRUCache所有的数据
  • 当一个Handle不被外部引用时,它会被LRU链表引用,表示可回收
  • 当cache的内存不足时,先回收LRU链表引用数据的内存

下面一张图展示了hashtable管理的内存和LRU链表管理的内存之间的关系:

LRUCacheShard关键类成员如下:

class LRUCacheShard : public CacheShard {public:LRUCacheShard();virtual ~LRUCacheShard();/* 向LRUCache中插入数据 */virtual Status Insert(const Slice& key, uint32_t hash, void* value,size_t charge,void (*deleter)(const Slice& key, void* value),Cache::Handle** handle,Cache::Priority priority) override;/* 从LRUCache中查找数据 */                      virtual Cache::Handle* Lookup(const Slice& key, uint32_t hash) override;/* 解引用一个Handle,视根据内存的使用情况和Handle的引用计数而定,该Handle不一定会被在cache中抹除 */virtual bool Release(Cache::Handle* handle,bool force_erase = false) override;/* 从LRUCache中抹除 */virtual void Erase(const Slice& key, uint32_t hash) override;private:void LRU_Remove(LRUHandle* e);void LRU_Insert(LRUHandle* e);/* 当高优先级链表引用的数据超过一个阈值时,将高优先级链表引用的数据,调整到低优先级链表上 */void MaintainPoolSize();void EvictFromLRU(size_t charge, autovector<LRUHandle*>* deleted);/** LRUCahche管理的内存上限。* 以下几个关于LRUCache的内存相关的数据指标,都仅仅只包括caller传入的charge,* 不包括LRUCache自身数据结构占用的内存*/size_t capacity_; /* 所有驻留在hashtable中的元素所占的内存大小 */size_t usage_; /* LRUList管理的内存大小 */size_t lru_usage_;/* 高优先级LRU链表管理的内存大小 */size_t high_pri_pool_usage_;/* 开启严格模式后,内存超限,则报错 */bool strict_capacity_limit_;/* 高优先级LRU链表能够管理的内存最大大小 */double high_pri_pool_capacity_;mutable port::Mutex mutex_;/* Dummy head of LRU list. */LRUHandle lru_;/* 低优先链表的链表头 */LRUHandle* lru_low_pri_;LRUHandleTable table_;
};

关于LRUCacheShard不同优先级链表的实现

上文中提到过,rocksdb的LRUCache是通过一个双向循环链表来实现LRU语义的,该循环链表有一个dummy的链表头lru_,链表的元素为LRUHandle,LRUHandle为LRUCache管理的最基本的元素,该对象用于封装上层调用者传来的value和key。
LRUCache有一个成员变量lru_low_pri_,用于指向低优先级的队列头。初始时LRU队列为空,每次有新元素插入时,对于高优先级元素会将其插入队列尾部,对于低优先级元素会将其插入低优先级队列的头部。比如,我们先插两个低优先级的元素,再插两个高优先级的元素,LRU链表的结构应该是这样的:

接着再次插入一个低优先级的元素:

如果LRU队列设置的高优先级的链表长度最多为2,那么我们再次插入一个高优先级元素后:

RocksDB LRUCache相关推荐

  1. rocksdb学习笔记

    rocksdb是在leveldb的基础上优化而得,解决了leveldb的一些问题. 主要的优化点 1.增加了column family,这样有利于多个不相关的数据集存储在同一个db中,因为不同colu ...

  2. RocksDB 架构

    文章目录 1.RocksDB 摘要 1.1.RocksDB 特点 1.2.基本接口 1.3.编译 2.LSM - Tree 2.1.Memtable 2.2.WAL 2.3.SST 2.4.Block ...

  3. RocksDB基本架构与原理介绍

    Rocksdb Flink提供基于流的有状态计算,除了提供实时数据流的处理能力,还需要将计算产生的状态存储起来. 为了满足状态存取需求,提供了memory.flie system.rocksdb三种类 ...

  4. rocksdb原理_RocksDB解析

    0. 存储引擎基础 存储引擎的基本功能和数据结构 一个存储引擎需要实现三个基本的功能: write(key, value)                                       ...

  5. rocksdb写放大_rocksdb理解

    rocksdb是在leveldb的基础上优化而得,解决了leveldb的一些问题. 主要的优化点 1.增加了column family,这样有利于多个不相关的数据集存储在同一个db中,因为不同colu ...

  6. 漫谈RocksDB(二)基础讲解——仿佛兮若轻云之蔽月,飘飘兮若流风之回雪

    前言 古话说得好:"工欲善其事必先利其器",要做好一件事情之前先把工具或者武器强化一下还是很值当的.所以本文将会把RocksDB的主要概念向大家讲解一下,方便后面具体内容的展开.本 ...

  7. RocksDB Java API 操作示例

    1. RocksDB特点 rocksDB 是一个可嵌入的,持久性的 key-value存储.基于Google的LevelDB,但提高了扩展性可以运行在多核处理器上,可以有效使用快速存储,支持IO绑定. ...

  8. 内存缓存LruCache的简单使用

    LruCache算法(Least Recently Used),也叫近期最少使用算法. 这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并 ...

  9. Rocksdb的事务(二):完整事务体系的 详细实现

    文章目录 1. 基本事务操作 1.1 TransactionDB -- Pessimistic 1.2 OptimisticTransactionDB 1.3 Read Uncommitted 1.4 ...

最新文章

  1. UVA 216 Getting in Line
  2. Microsoft Visual Studio 2012 添加实体数据模型
  3. 基于SSM实现绿色有机产品直营网
  4. HTML/CSS快速入门
  5. php mssql 端口,MSSQL_SQL Server端口更改后的数据库连接方式,SQL Server端口,大家可以通过quot - phpStudy...
  6. 卷积神经网络初探 | 数据科学家联盟 http://dataunion.org/20942.html
  7. Hivesql-高级进阶技巧
  8. pandas及numpy笔记
  9. Jenkins插件安装
  10. Chrome浏览器的便捷使用方式
  11. win10开启虚拟化服务器,Windows10开启Hyper-V虚拟机管理器
  12. 【YOLOV5-5.x 源码解读】plots.py
  13. (附代码)数独大作业【读取数独,解数独,生成唯一解数独(随机,特定形状,不同难度生成),玩数独】
  14. iphone各版本分辨率
  15. 马斯克用数字孪生开启航天工业大时代,工互2.0来了吗?
  16. 一个好的PS笔刷(笔触)下载论坛
  17. selenium+Java同时开启多个浏览器并行测试用例
  18. 是的,奈学教育一周年了!
  19. EM(期望最大化)聚类详细推导
  20. 云原生应用的12要素

热门文章

  1. 软件测试怎么有效的降低测试轮次
  2. loam特征的合理性校验
  3. 中图分类法----F 经济
  4. SSM后台管理系统开发实战
  5. 我最喜欢的(3)——拜金小姐陈珊妮
  6. Youtube 上最赚钱的人,前三名我哭了两次
  7. arduino控制小车转向_【雕爷学编程】Arduino动手做(4)---振动传感器模块
  8. UG8.0塑胶模具设计全3D设计过程视频教程
  9. 【读书笔记】《游戏测试精通》思维导图
  10. Mysql主键设计-转拉钩教育