当前位置: 首页 > news >正文

【LevelDB】memtable、immutable memtable的切换源码

本文主要分析leveldb项目的MakeRoomForWrite方法及延伸出的相关方法。
努力弄清memtable 和 immutable memtable的切换过程细节,

背景总结:

LevelDB 是一个基于 Log-Structured Merge-Tree (LSM Tree) 的高性能键值存储系统。
在 LevelDB 中,MemTable 和 SSTable 是两种关键的数据结构,它们共同支持快速的读写操作和高效的存储管理。

MemTable 是 LevelDB 中的一个内存数据结构,它提供了快速的键值对读写能力。
SSTable(Sorted String Table)是 LevelDB 中用于持久化存储数据的结构。

当 MemTable 达到一定大小时,LevelDB 会将其转换为一个不可变的 memtable。这个过程称为 MemTable 切换(MemTable Switch)。新的 MemTable 会被创建,用于处理新的写入操作。被切换的 MemTable 会被持久化到磁盘上,成为一个 SSTable。这个过程通常涉及到写入一个 SSTable 文件,并可能触发 Compaction 操作来优化存储结构。

通过这种方式,LevelDB 能够在提供快速写入和读取操作的同时,有效地管理内存和磁盘空间,保持长期的存储效率。

有了以上基本知识背景后,我们来看源码怎么实现的?

MakeRoomForWrite源码分析

主要逻辑在db_impl.cc 的MakeRoomForWrite方法里。
这个方法的调用点在DBImpl::Write,即写数据的时候。

// REQUIRES: mutex_ is held
// REQUIRES: this thread is currently at the front of the writer queue
Status DBImpl::MakeRoomForWrite(bool force) {// 这个方法需要持有锁。mutex_.AssertHeld();assert(!writers_.empty());bool allow_delay = !force;Status s;while (true) {// 如果后台有error,将error赋给Status对象,然后跳出while循环if (!bg_error_.ok()) {// Yield previous errors = bg_error_;break;// 如果没有error,允许写延迟并且当前level0级别的文件数大于阈值。// 那这时就slow down writers。休眠1ms。期间释放mutex_, 休眠结束之后再获取mutex_} else if (allow_delay && versions_->NumLevelFiles(0) >=config::kL0_SlowdownWritesTrigger) {// We are getting close to hitting a hard limit on the number of// L0 files.  Rather than delaying a single write by several// seconds when we hit the hard limit, start delaying each// individual write by 1ms to reduce latency variance.  Also,// this delay hands over some CPU to the compaction thread in// case it is sharing the same core as the writer.mutex_.Unlock();env_->SleepForMicroseconds(1000);allow_delay = false;  // Do not delay a single write more than oncemutex_.Lock();// 走到下面这个分支,说明level0级别的文件数还没超过阈值。并且当前正在使用的memtable// 的内存使用小于4MB,说明还有空间预留给写操作,直接退出循环。// 注:预估内存使用情况使用的是leveldb自己实现的内存管理库Arena。} else if (!force &&(mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {// There is room in current memtablebreak;// 走到下面这个分支,说明当前memtable没有足够空间给写操作了。并且已经有一个immutable memtable存在了,// 此时不能继续创建immutable memtable了,打印一下日志,等待后台任务发出唤醒信号(imm_数据已经被flush到磁盘,并且引用被销毁)。} else if (imm_ != nullptr) {// We have filled up the current memtable, but the previous// one is still being compacted, so we wait.Log(options_.info_log, "Current memtable full; waiting...\n");background_work_finished_signal_.Wait();// 到下面这个分支,说明imm_指针为null,判断当前level0级别文件个数是否超过12个// 超过12个就需要等待后台任务发信号唤醒(compact结束)} else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {// There are too many level-0 files.Log(options_.info_log, "Too many L0 files; waiting...\n");background_work_finished_signal_.Wait();// 走到最后这个分支里,说明可以直接创建immutable memtable。} else {// 尝试切换到新的memtable,并且触发旧的文件的compaction。// Attempt to switch to a new memtable and trigger compaction of oldassert(versions_->PrevLogNumber() == 0);uint64_t new_log_number = versions_->NewFileNumber();WritableFile* lfile = nullptr;// 创建新的日志文件。用lfile指针指向。s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);if (!s.ok()) {// Avoid chewing through file number space in a tight loop.versions_->ReuseFileNumber(new_log_number);break;}// 删除当前日志文件的Writer指针	delete log_;// 关闭旧的日志文件 s = logfile_->Close();if (!s.ok()) {// We may have lost some data written to the previous log file.// Switch to the new log file anyway, but record as a background// error so we do not attempt any more writes.//// We could perhaps attempt to save the memtable corresponding// to log file and suppress the error if that works, but that// would add more complexity in a critical code path.RecordBackgroundError(s);}// 释放旧的日志文件对象delete logfile_;// logfile_指针指向新创建的日志文件logfile_ = lfile;logfile_number_ = new_log_number;// log_指针指向新日志文件创建出来的Writer对象log_ = new log::Writer(lfile);// imm_指针指向旧的mem_,即immutable memtable指向当前的memtable。imm_ = mem_;// has_imm_是个原子bool。has_imm_.store(true, std::memory_order_release);// mem_指针指向一个新的MemTable。mem_ = new MemTable(internal_comparator_);// 增加mem_的引用计数mem_->Ref();force = false;  // Do not force another compaction if have room// 可能会触发compaction。MaybeScheduleCompaction();}}return s;
}

TODO:
1、leveldb里NewWritableFile、LogFileName。

相关文章:

【LevelDB】memtable、immutable memtable的切换源码

本文主要分析leveldb项目的MakeRoomForWrite方法及延伸出的相关方法。 努力弄清memtable 和 immutable memtable的切换过程细节&#xff0c; 背景总结&#xff1a; LevelDB 是一个基于 Log-Structured Merge-Tree (LSM Tree) 的高性能键值存储系统。 在 LevelDB 中&#xff0…...

力扣面试150 x 的平方根 二分 换底法 牛顿迭代法 一题多解

Problem: 69. x 的平方根 思路 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f496; 袖珍计算器算法 class Solution {public int mySqrt(int x){if (x 0)return 0; // Math.exp(3)&#xff1a;e的三次方int ans (int) Math.exp(0.5 * Math.log(x));return (long) (an…...

【JavaScript】JavaScript 程序流程控制 ⑤ ( 嵌套 for 循环 | 嵌套 for 循环概念 | 嵌套 for 循环语法结构 )

文章目录 一、嵌套 for 循环1、嵌套 for 循环概念2、嵌套 for 循环语法结构 二、嵌套 for 循环案例1、打印三角形2、打印乘法表 一、嵌套 for 循环 1、嵌套 for 循环概念 嵌套 for 循环 是一个 嵌套的 循环结构 , 其中一个 for 循环 位于另一个 for 循环的内部 , 分别是 外层 f…...

情感计算:大模型在情感识别与交互优化中的作用

情感计算&#xff1a;大模型在情感识别与交互优化中的作用 1. 背景介绍 情感计算&#xff08;Affective Computing&#xff09;是人工智能领域的一个重要分支&#xff0c;它致力于使计算机能够识别、理解、处理和模拟人类的情感。随着深度学习、大数据和计算能力的飞速发展&a…...

集合系列(十四) -ConcurrentHashMap详解

一、摘要 在之前的集合文章中&#xff0c;我们了解到 HashMap 在多线程环境下操作可能会导致程序死循环的线上故障&#xff01; 既然在多线程环境下不能使用 HashMap&#xff0c;那如果我们想在多线程环境下操作 map&#xff0c;该怎么操作呢&#xff1f; 想必阅读过小编之前…...

数据结构面试题

1、数据结构三要素&#xff1f; 逻辑结构、物理结构、数据运算 2、数组和链表的区别&#xff1f; 数组的特点&#xff1a; 数组是将元素在内存中连续存放&#xff0c;由于每个元素占用内存相同&#xff0c;可以通过下标迅速访问数组中任何元素。数组的插入数据和删除数据效率低…...

python爬虫之xpath入门

文章目录 一、前言参考文档&#xff1a; 二、xpath语法-基础语法常用路径表达式举例说明 三、xpath语法-谓语表达式举例注意 四、xpath语法-通配符语法实例 五、选取多个路径实例 六、Xpath Helper安装使用说明例子&#xff1a; 七、python中 xpath 的使用安装xpath 的依赖包xm…...

TikTok云手机是什么原理?

社交媒体的快速发展和普及&#xff0c;TikTok已成为全球最受欢迎的短视频平台之一&#xff0c;吸引了数以亿计的用户。在TikTok上&#xff0c;许多用户和内容创作者都希望能够更灵活地管理和运营多个账号&#xff0c;这就需要借助云手机技术。那么&#xff0c;TikTok云手机究竟…...

24.3.24 《CLR via C#》 笔记10

第十三章 接口 类和接口继承 CLR不支持多继承&#xff0c;因此所有托管编程语言都不支持任何类都从且只能从一个类派生&#xff08;最终从Object类派生&#xff09;定义接口实际只是对一组方法进行了统一的命名&#xff0c;类通过指定接口名称来继承接口&#xff0c;且必须显式…...

SpringBoot 3整合Elasticsearch 8

这里写自定义目录标题 版本说明spring boot POM依赖application.yml配置新建模型映射Repository简单测试完整项目文件目录结构windows下elasticsearch安装配置 版本说明 官网说明 本文使用最新的版本 springboot: 3.2.3 spring-data elasticsearch: 5.2.3 elasticsearch: 8.1…...

突破编程_C++_查找算法(分块查找)

1 算法题 &#xff1a;使用分块算法在有序数组中查找指定元素 1.1 题目含义 在给定一个有序数组的情况下&#xff0c;使用分块查找算法来查找数组中是否包含指定的元素。分块查找算法是一种结合了顺序查找和二分查找思想的算法&#xff0c;它将有序数组划分为若干个块&#x…...

学习java第二十二天

IOC 容器具有依赖注入功能的容器&#xff0c;它可以创建对象&#xff0c;IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例&#xff0c;控制权由程序员控制&#xff0c;而"控制反转"是指new实例工作不由程序员来做而是交给Sp…...

每天学习一个Linux命令之systemctl

每天学习一个Linux命令之systemctl 介绍 在Linux系统中&#xff0c;systemctl命令是Systemd初始化系统的核心管理工具之一。systemd是用来启动、管理和监控运行在Linux上的系统的第一个进程&#xff08;PID 1&#xff09;&#xff0c;它提供了一整套强大的工具和功能&#xf…...

【机器学习入门】人工神经网络(二)卷积和池化

系列文章目录 第1章 专家系统 第2章 决策树 第3章 神经元和感知机 识别手写数字——感知机 第4章 线性回归 第5章 逻辑斯蒂回归和分类 第5章 支持向量机 第6章 人工神经网络(一) 文章目录 系列文章目录前言一、卷积神经连接的局部性平移不变性 二、卷积处理图像的效果代码二、…...

公司内部局域网怎么适用飞书?

随着数字化办公的普及&#xff0c;企业对于内部沟通和文件传输的需求日益增长。飞书作为一款集成了即时通讯、云文档、日程管理、视频会议等多种功能的智能协作平台&#xff0c;已经成为许多企业提高工作效率的首选工具。本文将详细介绍如何在公司内部局域网中应用飞书&#xf…...

JVM的知识

什么是JVM 1.JVM&#xff1a; JVM其实就是运行在 操作系统之上的一个特殊的软件。 2.JVM的内部结构&#xff1a; &#xff08;1&#xff09;因为栈会将执行的程序弹出栈。 &#xff08;2&#xff09;垃圾99%的都是在堆和方法区中产生的。 类加载器&#xff1a;加载class文件。…...

大模型日报2024-03-24

利用LLMs评分及解释K-12科学答案 摘要: 本文研究了在K-12级科学教育中使用大型语言模型&#xff08;LLMs&#xff09;对短答案评分及解释。研究采用GPT-4结合少量样本学习和活跃学习&#xff0c;通过人机协作提供有意义的评估反馈。 MathVerse&#xff1a;多模态LLM解数学题效果…...

Android kotlin全局悬浮窗全屏功能和锁屏页面全屏悬浮窗功能一

1.前言 在进行app应用开发中,在实现某些功能中要求实现悬浮窗功能,分为应用内悬浮窗 ,全局悬浮窗和 锁屏页面悬浮窗功能 等,接下来就来实现这些悬浮窗全屏功能,首选看下第一部分功能实现 2.kotlin全局悬浮窗全屏功能和锁屏页面全屏悬浮窗功能一分析 悬浮窗是属于Androi…...

图像识别在安防领域的应用

图像识别技术在安防领域有着广泛的应用&#xff0c;它通过分析和理解图像中的视觉信息&#xff0c;为安防系统提供了强大的辅助功能。以下是一些主要的应用领域&#xff1a; 人脸识别&#xff1a;人脸识别技术是安防领域中最常见的应用之一。它可以帮助系统识别和验证个人身份…...

前端面试集中复习 - http篇

1. http请求方式 HTTP请求方式有哪些&#xff1a;GET POST PUT DELETE OPTIONS 1) GET POST 的区别&#xff1f; 场景上&#xff1a; GET 用于获取资源而不对服务器资源做更改提交的请求&#xff0c;多次执行结果一致。用于获取静态数据&#xff0c;幂等。 POST&#xff1…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...