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

相关文章

linux重启命令有哪些? 7个实用的Linux系统重启命令汇总

《linux重启命令有哪些?7个实用的Linux系统重启命令汇总》Linux系统提供了多种重启命令,常用的包括shutdown-r、reboot、init6等,不同命令适用于不同场景,本文将详细... 在管理和维护 linux 服务器时,完成系统更新、故障排查或日常维护后,重启系统往往是必不可少的步骤。本文

Mac系统下卸载JAVA和JDK的步骤

《Mac系统下卸载JAVA和JDK的步骤》JDK是Java语言的软件开发工具包,它提供了开发和运行Java应用程序所需的工具、库和资源,:本文主要介绍Mac系统下卸载JAVA和JDK的相关资料,需... 目录1. 卸载系统自带的 Java 版本检查当前 Java 版本通过命令卸载系统 Java2. 卸载自定

基于Python实现一个简单的题库与在线考试系统

《基于Python实现一个简单的题库与在线考试系统》在当今信息化教育时代,在线学习与考试系统已成为教育技术领域的重要组成部分,本文就来介绍一下如何使用Python和PyQt5框架开发一个名为白泽题库系... 目录概述功能特点界面展示系统架构设计类结构图Excel题库填写格式模板题库题目填写格式表核心数据结构

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Windows 系统下 Nginx 的配置步骤详解

《Windows系统下Nginx的配置步骤详解》Nginx是一款功能强大的软件,在互联网领域有广泛应用,简单来说,它就像一个聪明的交通指挥员,能让网站运行得更高效、更稳定,:本文主要介绍W... 目录一、为什么要用 Nginx二、Windows 系统下 Nginx 的配置步骤1. 下载 Nginx2. 解压

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

windows系统上如何进行maven安装和配置方式

《windows系统上如何进行maven安装和配置方式》:本文主要介绍windows系统上如何进行maven安装和配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录1. Maven 简介2. maven的下载与安装2.1 下载 Maven2.2 Maven安装2.

使用Python实现Windows系统垃圾清理

《使用Python实现Windows系统垃圾清理》Windows自带的磁盘清理工具功能有限,无法深度清理各类垃圾文件,所以本文为大家介绍了如何使用Python+PyQt5开发一个Windows系统垃圾... 目录一、开发背景与工具概述1.1 为什么需要专业清理工具1.2 工具设计理念二、工具核心功能解析2.

Linux系统之stress-ng测压工具的使用

《Linux系统之stress-ng测压工具的使用》:本文主要介绍Linux系统之stress-ng测压工具的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、理论1.stress工具简介与安装2.语法及参数3.具体安装二、实验1.运行8 cpu, 4 fo

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe