当前位置: 首页 > 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…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...