大白话解析LevelDB:TableCache

文章目录

    • TableCache 的构造函数
    • TableCache::Get
      • 在 Cache 中查找指定的 SST
      • 从 SST 中查找指定的 Key
    • TableCache::NewIterator
    • TableCache::Evict

TableCacheLevelDB中的作用是管理和缓存SST(Sorted String Tables)的读取。

为了提高读取效率,TableCache会缓存已打开的SST。这样,对同一SST的多次读取操作就不需要每次都打开文件。

我们来看下TableCache里都有哪些接口:

class TableCache {public:// 构造时接受一个 entries 参数,用于指定最大的缓存 SST 数量。当缓存的 SST 数量超过// 这个限制时,TableCache 会根据某种策略(如最近最少使用,LRU)从 Cache 里移除一些/ SST。TableCache(const std::string& dbname, const Options& options, int entries);~TableCache();// 返回一个指定 SST 的迭代器,用于遍历 SST 中的键值对。Iterator* NewIterator(const ReadOptions& options, uint64_t file_number, uint64_t file_size,Table** tableptr = nullptr);// 从指定 SST 中查找某个 Key。如果这个 Key 找到了,则调用 handle_result 函数。Status Get(const ReadOptions& options, uint64_t file_number, uint64_t file_size, const Slice& k,void* arg, void (*handle_result)(void*, const Slice&, const Slice&));// 将某个 SST 从 TableCache 中移除。void Evict(uint64_t file_number);
};

TableCache 的构造函数

TableCache::TableCache(const std::string& dbname, const Options& options, int entries): env_(options.env), dbname_(dbname), options_(options), cache_(NewLRUCache(entries)) {}

TableCache的构造函数里主要是cache_的初始化,构造一个LRUCache

TableCache其实是一个包装类,核心是cache_TableCache的所有接口都是对cache_的封装,方便使用。

NewLRUCache(entries)是个典型的工厂模式,用于创建一个LRUCache对象:

Cache* NewLRUCache(size_t capacity) { return new ShardedLRUCache(capacity); }

LRUCache的实现可移步参考大白话解析LevelDB:ShardedLRUCache。

使用工厂模式的好处是替换方便,如果我们想要替换成其他类型的LRUCache,比如SingleLRUCache,只需要修改NewLRUCache函数即可,而不需要每一处构造LRUCache的上层代码。

TableCache::Get

TableCache::Get用于从Cache中查找指定的SST,再从这个SST中查找指定的Key

如果SST不在Cache中,TableCache会打开这个SST,并将其添加到Cache中。

Status TableCache::Get(const ReadOptions& options, uint64_t file_number, uint64_t file_size,const Slice& k, void* arg,void (*handle_result)(void*, const Slice&, const Slice&)) {// 在 Cache 中找到指定的 SST。// 如果目标 SST 不在缓存中,它会打开文件并将其添加到 Cache。// handle 指向 Cache 中的 SST Item。Cache::Handle* handle = nullptr;Status s = FindTable(file_number, file_size, &handle);if (s.ok()) {// 通过 handle 在 cache 中获取 SST 对应的 Table 对象。Table* t = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;// 调用 Table::InternalGet() 方法从 SST 中查找指定的 key。s = t->InternalGet(options, k, arg, handle_result);cache_->Release(handle);}return s;
}

在 Cache 中查找指定的 SST

TableCache::Get的核心是FindTable函数,它用于在Cache中查找指定的SST

先尝试在cache_中查找指定的SST,如果找到了,就直接返回handle

如果没找到,就打开这个SST,并将其添加到cache_中,然后再返handle

Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle** handle) {Status s;// 将 file_number 编码为 fixed64,作为 key 到// cache_ 中查找 handle。char buf[sizeof(file_number)];EncodeFixed64(buf, file_number);Slice key(buf, sizeof(buf));*handle = cache_->Lookup(key);// 如果 cache_ 中木有找到,就打开该 SST 文件,并将其添加到 cache_ 中。if (*handle == nullptr) {// 根据 file_number 构造出 SST 的文件名。// 早期版本的 LevelDB 使用的是 .sst 后缀,后来改为了 .ldb。// 为了兼容这两种命名方式,这里会尝试两种后缀。// TableFileName() 会构建 .ldb 后缀的 SST 文件名,// SSTTableFileName() 会构建 .sst 后缀的 SST 文件名。std::string fname = TableFileName(dbname_, file_number);RandomAccessFile* file = nullptr;Table* table = nullptr;s = env_->NewRandomAccessFile(fname, &file);if (!s.ok()) {std::string old_fname = SSTTableFileName(dbname_, file_number);if (env_->NewRandomAccessFile(old_fname, &file).ok()) {s = Status::OK();}}// SST 文件打开后,通过 Table::Open 创建一个 Table 对象。if (s.ok()) {s = Table::Open(options_, file, file_size, &table);}if (!s.ok()) {// 如果创建 Table 对象失败,就关闭 SST 文件的句柄。assert(table == nullptr);delete file;} else {// Table 对象创建成功,将其添加到 cache_ 中。TableAndFile* tf = new TableAndFile;tf->file = file;tf->table = table;*handle = cache_->Insert(key, tf, 1, &DeleteEntry);}}return s;
}

TableCache::FindTable里的核心操作是cache_->Lookupcache_->Insert

其实现细节可移步参考 cache_->Lookup 的实现与 cache_->Insert 的实现。

env_->NewRandomAccessFile(fname, &file)的实现细节可移步参考大白话解析LevelDB: Env。

Table::Open(options_, file, file_size, &table)的实现细节可移步参考大白话解析LevelDB: Table。

从 SST 中查找指定的 Key

找到SST后就好说了,从SST中查找指定的Key的逻辑甩给Table::InternalGet函数就行了。

t->InternalGet(options, k, arg, handle_result)的实现细节可移步参考大白话解析LevelDB: Table。

TableCache::NewIterator

TableCache::NewIteratorTableCache::Get类似,先在Cache中查找指定的SST,再把NewIterator的逻辑甩给Table::NewIterator函数。

Iterator* TableCache::NewIterator(const ReadOptions& options, uint64_t file_number,uint64_t file_size, Table** tableptr) {if (tableptr != nullptr) {*tableptr = nullptr;}// 在 Cache 中找到指定的 SST。// 如果目标 SST 不在缓存中,它会打开文件并将其添加到 Cache。// handle 指向 Cache 中的 SST Item。Cache::Handle* handle = nullptr;Status s = FindTable(file_number, file_size, &handle);if (!s.ok()) {return NewErrorIterator(s);}// 通过 handle 在 cache 中获取 SST 对应的 Table 对象。Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;// 调用 Table::NewIterator() 方法创建该 SST 的 Iterator。Iterator* result = table->NewIterator(options);result->RegisterCleanup(&UnrefEntry, cache_, handle);if (tableptr != nullptr) {*tableptr = table;}return result;
}

table->NewIterator(options)的实现细节可参考大白话解析LevelDB: Table。

TableCache::Evict

file_number包装成一个cache_能识别的Key,再调用cache_->Erase函数,将这个Keycache_中移除。

void TableCache::Evict(uint64_t file_number) {// 将 file_number 编码为 fixed64,// 作为 cache_ 中的 key,将该 key 从// cache_ 中移除。char buf[sizeof(file_number)];EncodeFixed64(buf, file_number);cache_->Erase(Slice(buf, sizeof(buf)));
}

cache_->Erase(Slice(buf, sizeof(buf)))的实现细节可移步参考大白话解析LevelDB:ShardedLRUCache。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux-Uboot命令

help命令 进入 uboot 的命令行模式后输入“help”或者“&#xff1f;”&#xff0c;然后按下回车即可查看当前 uboot 所支持的命令。 查看某一个命令的帮助信息&#xff1a;&#xff1f;命令名称 或 help命令名称 信息查询命令 常用的和信息查询有关的命令有 3 个…

力扣Hot100

力扣100题easy 1. 两数之和 时间空间复杂度为O(N)&#xff0c;思路是&#xff1a;创建一个哈希表&#xff0c;对于每一个 x&#xff0c;先查询哈希表中是否存在 target - x&#xff0c;然后将 x 插入到哈希表中&#xff0c;即可保证不会让 x 和自己匹配。 class Solution {p…

Cookie、Session和JWT

摘要&#xff1a;Cookie、Session和JWT都不是什么新的技术了&#xff0c;最近用到了就比较和总结下。 我们知道http协议是无状态的&#xff0c;用户登录后如何验证和保存用户状态呢&#xff1f;下面来介绍 1. 使用Cookie和Session验证登录状态 session是保存在服务端的一种数…

STM32串口通信(发送与接收数据)

文章目录 前言一、介绍部分通信接口术语解释 串口通信简介硬件电路电平标准串口参数串口时序USART简介USART框图USRAT基本结构数据帧起始位检测波特率发生器CH340G 二、实例部分使用串口发送数据接线图代码实现重定向printf需要勾上Use MicroLIB中文不乱码方法 串口的发送与接收…

C++ 之LeetCode刷题记录(三十六)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅。 目标&#xff1a;执行用时击败90%以上使用 C 的用户。 16. 最接近的三数之和 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你…

题目 1036: [编程入门]带参数宏定义练习

问题描述&#xff1a; 定义一个带参的宏&#xff0c;使两个参数的值互换&#xff0c;并写出程序&#xff0c;输入两个数作为使用宏时的实参。输出已交换后的两个值。 样例输入&#xff1a; 1 2 样例输出&#xff1a; 2 1 问题分析&#xff1a; 无 代码…

Qt篇——QTableWidget常用设置

//表格颜色间隔显示 ui->originDataTable->setAlternatingRowColors(true); //设置表格列数 ui->originDataTable->setColumnCount(3); //设置表格头 QStringList headerList1; headerList1 << QString::from…

LeetCode #2605 从两个数字数组里生成最小数字

题目 给你两个只包含 1 到 9 之间数字的数组 nums1 和 nums2 &#xff0c;每个数组中的元素 互不相同 &#xff0c;请你返回 最小 的数字&#xff0c;两个数组都 至少 包含这个数字的某个数位。 示例 1&#xff1a; 输入&#xff1a;nums1 [4,1,3], nums2 [5,7] 输出&#…

Python 从文件中读取JSON 数据并解析转存

文章目录 文章开篇Json简介Json数据类型Json硬性规则Json数据转化网站Json和Dict类型转换json模块的使用Python数据和Json数据的类型映射json.dumps1.字典数据中含有**存在中文**2.json数据通过缩进符**美观输出**3.对Python数据类型中键进行**排序输出**4.json数据**分隔符的控…

【软件测试】接口调不通排查分析+常遇面试题总结

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、接口调不通&am…

【论文阅读】深度学习在过冷沸腾气泡动力学分割中的应用

Application of deep learning for segmentation of bubble dynamics in subcooled boiling 深度学习在过冷沸腾气泡动力学分割中的应用 期刊信息&#xff1a;International Journal of Multiphase Flow 2023 级别&#xff1a;EI检索 SCI升级版工程技术2区 SCI基础版工程技术3区…

(libusb) usb口自动刷新

文章目录 libusb自动刷新程序Code目录结构Code项目文件usb包code包 效果描述重置reset热拔插使用 END libusb 在操作USB相关内容时&#xff0c;有一个比较著名的库就是libusb。 官方网址&#xff1a;libusb 下载&#xff1a; 下载源码官方编好的库github&#xff1a;Release…

新的一年,如何优化企业库存管理?

随着社会的发展和经济的不断增长&#xff0c;库存管理成为了企业运营中非常重要的一环。库存作为企业的资产之一&#xff0c;直接影响着企业的盈利能力和竞争优势。因此&#xff0c;对企业库存进行科学的分析和管理&#xff0c;成为了确保企业持续稳定发展的必要手段之一。企业…

比亚迪领航新能源时代:汉唐传承,品牌力量

比亚迪&#xff0c;以中国文化的深度与自信&#xff0c;为新能源汽车领域注入强大动力。汉唐车型&#xff0c;不仅承载着中国古代文明的辉煌&#xff0c;更以其创新技术和环保理念&#xff0c;终结油电之争&#xff0c;让燃油车再次破防。作为销量冠军&#xff0c;比亚迪品牌的…

android开发与实战,那些年Android面试官常问的知识点

前言 在做android项目开发时&#xff0c;大家都知道如果程序出错了&#xff0c;会弹出来一个强制退出的弹 出框&#xff0c;这个本身没什么问题&#xff0c;但是这个UI实在是太丑了&#xff0c;别说用户接受不了&#xff0c;就连 我们自己本身可能都接受不了。虽然我们在发布程…

1.2 debug的六种指令的使用,四个通用寄存器

汇编语言 首先进入环境 mount c d:masm //把c挂载在d盘中的masm当中 c: //进入c&#xff0c;进入到编译环境 dir //查看文件&#xff0c;可有可无Debug是DOS、Windows都提供的实模式&#xff08;8086 方式&#xff09;程序的调试工具。使用它可以查看CPU各种寄存器中的内容…

C语言基础18 循环

们可能需要多次执行同一块代码。一般情况下&#xff0c;语句是按顺序执行的&#xff1a;函数中的第一个语句先执行&#xff0c;接着是第二个语句&#xff0c;依此类推。 编程语言提供了更为复杂执行路径的多种控制结构。 循环语句允许我们多次执行一个语句或语句组&#xff0…

为什么模型需要激活函数?

模型需要激活函数的原因主要是为了增加神经网络模型的非线性能力。没有激活函数&#xff0c;不论神经网络有多少层&#xff0c;它本质上还是一个线性回归模型&#xff0c;这意味着它只能学习输入和输出之间的线性关系。激活函数通过引入非线性因素&#xff0c;使得神经网络能够…

leetcode刷题(剑指offer) 46.全排列

46.全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&#xff1a; 输入&#…

计算机组成原理

计算机组成原理是计算机科学中的一门重要课程&#xff0c;主要研究计算机硬件系统的基本组成和工作原理。以下是一份关于计算机组成原理的3000字概述&#xff0c;由于篇幅限制&#xff0c;我将提供一个摘要版本。若需要更详细的内容&#xff0c;请随时告知。 一、引言 计算机&…