leveldb源码剖析---缓存系统

2023-12-16 16:38

本文主要是介绍leveldb源码剖析---缓存系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

通过前面的分析可以知道,leveldb为了提高写的性能,牺牲了部分的读性能。最差的情况可能需要遍历各个level中的每个文件。为了缓解读性能,leveldb引入了缓存机制,当然,版本信息中包含各个level的文件元信息在一定程度上也可以提高读性能。


leveldb提供的缓存系统的底层数据结构是一个开链哈希

class ShardedLRUCache : public Cache :LRUCache shard_[kNumShards];
  • 1
  • 2
  • 3

它是一个数组,其中数组中的每个元素包含两个链表,和一个用于加速链表元素查找的哈希表 table_。

class LRUCache:....LRUHandle lru_;LRUHandle in_use_; HandleTable table_;....
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

链表中的每个元素就表示一个缓存单元–LRUHandle

LRUHandle :void* value;char key_data[1];....LRUHandle* next_hash; //这个指针是用来将LRUHandle链到hashtable中的LRUHandle* next;LRUHandle* prev;...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里我们只关注这一部分元素。首先是链表元素的主要内容,我们可以看到,每个链表元素都是一个key-value形式的数据

1. 其中key 为对应sstable的file_number,通过它可以打开磁盘上的其所指向的sstable文件。
2. value为TableAndFile,里面包含这个sstable文件的许多元信息,包括 index_block,metadataindex_block信息等。

这里需要提一下,前面在分析版本控制时,可以看到每个版本都会包含所有level的各个文件的元信息,需要注意的是,版本信息里里面的元信息为FileMetaData,和它相比,TableAndFile包含有文件的更多信息。


这里我们简单理一下FileMetaData和TableAndFile是怎么互相帮助提高读性能的:
当用户调用leveldb的get函数,期望获得对应key的value时
1. leveldb先从版本信息中检查各个level中的各个文件的FileMetaData,查看这个key是否有可能存在于对应的sstable中
2. 如果有可能存在在这个sstable中,则根据这个sstable文件的FileMetaData提供的file_number在缓存中找到对应的TableAndFile;当然,如果缓存中没有这个sstable的TableAndFile,则从磁盘中将其读进来。
3. 进一步根据TableAndFile中的index_block,metadata_block等信息确定该key是否在这个sstable中。

具体的细节可以从

Status DBImpl::Get(const ReadOptions& options,const Slice& key,std::string* value)
  • 1
  • 2
  • 3

函数的实现中找到


下面我们继续分析缓存系统:

除了存储缓存具体数据的元素之外,缓存链表中还包括链表组织的数据
next,prev表示这是一个双向链表。它将缓存系统中的所有sstable缓存元数据组织了起来。前面讲到,为了方便缓存查找,leveldb使用了开链哈希。但是开链哈希也有可能存在问题,比如如果开链数组中单个元素指向的链表过长,则对这个链表的线性扫描还是会非常耗费时间。为了解决这个问题,leveldb在每个链表上再建立了一层哈希。这就是结构中next_hash的作用。因此leveldb利用了二维哈希来缓解了对于开链哈希可能存在的单个链表过长的问题。

如果我们深入看HandleTable的代码,就会发现,它也是一个开链哈希。通过next_hash将元素链在这个哈希表中。

最后,缓存系统中有两条链表 :in_lru_和in_use_。

作用是显而易见的。我们知道链表中的每个元素(LRUHandle)用

 uint32_t refs; 
  • 1

来做为引用计数标记该元素目前正在被多少个用户使用,显然如果refs>0,这个元素是不能从缓存中被删除的。这里需要注意的是,缓存系统本身也是这个元素的一个用户,因此从 Cache::Handle* LRUCache::Insert函数中可以看到,每个插入新插入的元素的refs都为2,表示它有两个用户,分别是
1. cache系统本身
2. 调用insert的用户

那很自然的一个问题是这个元素什么时候才被删除呢?自然是它的用户数为0的时候。当一个元素的引用计数为1时,说明它只有cache系统一个用户,此时,将它移动到lru_链表中,在这个链表中的元素随时可以被删除掉,因为没有上层用户对它使用了。它的真正删除发生在缓存系统的容量满载时,判断满载自然也是在 LRUCache::Insert函数中。当元素只cache一个用户时,则放在lru_链表中,当缓存满载时,从lru_链表中删除。如果有上层用户在使用这个元素,则将它放在in_use_链表中。缓存系统的负载是使用

 size_t usage_;
  • 1

来记录的。缓存系统的容量是用

 size_t capacity_;
  • 1

记录的。

至此leveldb的缓存系统的主要部分就讲完了。


总结

leveldb引入了缓存系统来改善它的读性能。缓存系统本质上是将最近读过的sstable文件的元信息(TableAndFile)放在内存中,以避免每次读取数据时都要直接读盘。在读取某个给定key的value时,leveldb首先通过版本信息找到可能包含该key的文件的file_number,然后通过这个file_number找到缓存系统中保存的更加完整的文件元信息。如果缓存系统中没有这个file_number对应的元素,则需要读盘,并在内存中创建对应这个sstable文件的TableAndFile,并插入缓存中。

缓存系统是通过二维开链哈希将缓存中所有的sstable的元信息组织起来的。并利用引用计数设计了二层的缓存,将暂时不用的元素也依旧缓存在系统中,只有负载过高时才真正删除。当然为了避免同步问题,对缓存元素的链表操作必须在临界区内。

这篇关于leveldb源码剖析---缓存系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/501160

相关文章

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资

TP-LINK/水星和hasivo交换机怎么选? 三款网管交换机系统功能对比

《TP-LINK/水星和hasivo交换机怎么选?三款网管交换机系统功能对比》今天选了三款都是”8+1″的2.5G网管交换机,分别是TP-LINK水星和hasivo交换机,该怎么选呢?这些交换机功... TP-LINK、水星和hasivo这三台交换机都是”8+1″的2.5G网管交换机,我手里的China编程has

使用Spring Cache时设置缓存键的注意事项详解

《使用SpringCache时设置缓存键的注意事项详解》在现代的Web应用中,缓存是提高系统性能和响应速度的重要手段之一,Spring框架提供了强大的缓存支持,通过​​@Cacheable​​、​​... 目录引言1. 缓存键的基本概念2. 默认缓存键生成器3. 自定义缓存键3.1 使用​​@Cacheab

基于Qt实现系统主题感知功能

《基于Qt实现系统主题感知功能》在现代桌面应用程序开发中,系统主题感知是一项重要的功能,它使得应用程序能够根据用户的系统主题设置(如深色模式或浅色模式)自动调整其外观,Qt作为一个跨平台的C++图形用... 目录【正文开始】一、使用效果二、系统主题感知助手类(SystemThemeHelper)三、实现细节

CentOS系统使用yum命令报错问题及解决

《CentOS系统使用yum命令报错问题及解决》文章主要讲述了在CentOS系统中使用yum命令时遇到的错误,并提供了个人解决方法,希望对大家有所帮助,并鼓励大家支持脚本之家... 目录Centos系统使用yum命令报错找到文件替换源文件为总结CentOS系统使用yum命令报错http://www.cppc