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

[LevelDB]LevelDB版本管理的黑魔法-为什么能在不锁表的情况下管理数据?

文章摘要

  1. LevelDB的日志管理系统是怎么通过双链表来进行数据管理
  2. 为什么LevelDB能够在不锁表的情况下进行日志新增

适用人群:

  1. 对版本管理机制有开发诉求,并且希望参考LevelDB的版本开发机制。
  2. 数据库相关从业者的专业人士。
  3. 计算机狂热爱好者,对计算机的存储机制有强烈技术追求的同志。

阅读建议:

  1. 作者本人功底有限不太可能考虑到所有读者的阅读细节,建议读者先通盘阅读下本文,先熟悉本文中会出现哪些关键概念和关键流程,并配合上AI工具对文章中个别流程进行细致理解。

LevelDB版本管理机制

核心抽象

在这里插入图片描述
主要分为

  1. 版本管理层:版本抽象相关的操作和逻辑。
  2. 文件管理层: 主要和文件磁盘上的物化数据打交道。
  3. 快照管理层:依托快照对外暴露固化查询的服务。
抽象职能
Version版本管理的最小单位,维护特定时刻的数据库状态,管理文件集合
VersionSet版本集合管理器,负责管理所有版本,维护当前版本,处理版本切换
VersionEdit版本变更记录,记录版本间的差异,支持变更的序列化和反序列化
Builder版本构建器,负责构建新版本,应用版本变更
Compaction压缩任务管理,处理文件压缩,生成新的版本变更
FileMetaData文件元数据,记录文件的基本信息(大小、范围等)
Manifest清单文件管理,持久化版本信息,支持数据库恢复
Snapshot数据库某一时刻的快照,提供一致性读取视图,基于序列号实现
SnapshotList快照列表管理,维护所有活跃的快照,管理快照的生命周期

这里面的重点是:

  • Version是整个版本管理机制的最小单元抽象
  • compaction 的机制非常复杂,本文不赘述,感兴趣移步: [LevelDB]揭秘LevelDB暗藏的合并秘技,Compaction内部的超神操作让工程师都惊呆了!

版本管理层(Version)核心逻辑

在这里插入图片描述

  1. 客户端向VersionSet抽象请求版本变更操作
  2. VersionSet 通过创建VersionEdit来记录一些当前操作的变更
  3. 使用Build模式来创建新版本并更新当前的版本

亮点设计:

  1. 使用新建Version的方式来实现无锁读取,简化并发控制。
  2. 使用Builder(构建者模式)来进行构建,对代码进行解耦。
  3. 使用VersionEdit进行增量更新,并且能够通过VersionEdit来进行日志记录。

源代码细节说明

客户端(通常理解是应用LevelDB的机器)调用LevelDB的LogAndApply接口来进行版本新增

// 调用入口
s = versions_->LogAndApply(&edit, &mutex_);

简单来说,就是生成一个新的版本Version,并添加到当前的版本管理链表中。
在这里插入图片描述
LogAndApply方法主要有以下的核心阶段(流程图见下文

  • 初始化一些必要参数,如log_number_(日志编号: 用于后续清理WAL无用日志), file_number(文件编号-用于实现文件的唯一性),Sequence(用于实现序列号唯一性)
    在这里插入图片描述
    源码参考:
  // 日志版本号-用于实现WAL 预写入机制-用于清理当时用不了的文件if (edit->has_log_number_) {assert(edit->log_number_ >= log_number_);assert(edit->log_number_ < next_file_number_);} else {edit->SetLogNumber(log_number_);}if (!edit->has_prev_log_number_) {edit->SetPrevLogNumber(prev_log_number_);}// file_number 文件编号-用于实现文件的唯一性  // sequence: 用于控制序列唯一性edit->SetNextFile(next_file_number_);edit->SetLastSequence(last_sequence_);
  • 构建新版本(包括对版本的压缩打分)
    在这里插入图片描述
  1. 创建新版本 -亮点: 使用Builder模式来构建新版本
  2. Apply 方法 用于根据edit中的信息来生成对应的build构造器
  3. SaveTo 方法 用于将build构造器中的信息应用到新的version中
  Version* v = new Version(this);{Builder builder(this, current_);builder.Apply(edit);builder.SaveTo(v);}// 计算 最佳压缩层级Finalize(v);
  • MANIFEST处理阶段, 这里的MANIFEST
    在这里插入图片描述
 // MANIFEST 文件处理std::string new_manifest_file;Status s;if (descriptor_log_ == nullptr) {// 日志assert(descriptor_file_ == nullptr);// 底层文件操作new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);if (s.ok()) {descriptor_log_ = new log::Writer(descriptor_file_);// 写入快照-本质上是向 Manifest 日志中写入当前的文件状态,防止记录丢失s = WriteSnapshot(descriptor_log_);}}
  • 文件同步阶段
    在这里插入图片描述
{mu->Unlock();if (s.ok()) {std::string record;edit->EncodeTo(&record);s = descriptor_log_->AddRecord(record);if (s.ok()) {s = descriptor_file_->Sync();}if (!s.ok()) {Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str());}}if (s.ok() && !new_manifest_file.empty()) {s = SetCurrentFile(env_, dbname_, manifest_file_number_);}// 重新获取锁mu->Lock();}
  • 完成安装阶段
    在这里插入图片描述
// 让基于VersionEdit和老版本if (s.ok()) {// 将新版本添加到版本链表AppendVersion(v);// 更新日志文件号log_number_ = edit->log_number_;prev_log_number_ = edit->prev_log_number_;} else {//  快照写入失败delete v;if (!new_manifest_file.empty()) {// 清理新创建的 MANIFEST 文件相关资源delete descriptor_log_;delete descriptor_file_;descriptor_log_ = nullptr;descriptor_file_ = nullptr;env_->RemoveFile(new_manifest_file);}}return s;
}

猜你喜欢

C++多线程: https://blog.csdn.net/luog_aiyu/article/details/145548529
一文了解LevelDB数据库读取流程:https://blog.csdn.net/luog_aiyu/article/details/145946636
一文了解LevelDB数据库写入流程:https://blog.csdn.net/luog_aiyu/article/details/145917173
关于LevelDB存储架构到底怎么设计的:https://blog.csdn.net/luog_aiyu/article/details/145965328?spm=1001.2014.3001.5502

PS

你的赞是我很大的鼓励
我是darkchink,一个计算机相关从业者&一个摩托佬&AI狂热爱好者
本职工作是某互联网公司数据相关工作,欢迎来聊,内推或者交换信息
vx 二维码见: https://www.cnblogs.com/DarkChink/p/18598402

相关文章:

[LevelDB]LevelDB版本管理的黑魔法-为什么能在不锁表的情况下管理数据?

文章摘要 LevelDB的日志管理系统是怎么通过双链表来进行数据管理为什么LevelDB能够在不锁表的情况下进行日志新增 适用人群: 对版本管理机制有开发诉求&#xff0c;并且希望参考LevelDB的版本开发机制。数据库相关从业者的专业人士。计算机狂热爱好者&#xff0c;对计算机的…...

bisheng系列(二)- 本地部署(前后端)

一、导读 环境&#xff1a;Ubuntu 24.04、open Euler 23.03、Windows 11、WSL 2、Python 3.10 、bisheng 1.1.1 背景&#xff1a;需要bisheng二开商用&#xff0c;故而此处进行本地部署&#xff0c;便于后期调试开发 时间&#xff1a;20250519 说明&#xff1a;bisheng前后…...

【网络编程】十二、两万字详解 IP协议

文章目录 Ⅰ. 基本概念1、网络层解决的问题2、保证数据可靠的从一台主机送到另一台主机的前提3、路径选择4、主机和路由器的区别 Ⅱ. IP协议格式IP如何将报头与有效载荷进行分离&#xff1f;IP如何决定将有效载荷交付给上层的哪一个协议&#xff1f;理解socket编程 Ⅲ. 分片与组…...

Linux探秘:驾驭开源,解锁高效能——基础指令

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...

WebSocket解决方案的一些细节阐述

今天我们来看看WebSocket解决方案的一些细节问题&#xff1a; 实际上&#xff0c;集成WebSocket的方法都有相关的工程挑战&#xff0c;这可能会影响项目成本和交付期限。在最简单的层面上&#xff0c;构建 WebSocket 解决方案似乎是添加接收实时更新功能的前进方向。但是&…...

大数据量下Redis分片的5种策略

随着业务规模的增长&#xff0c;单一Redis实例面临着内存容量、网络带宽和计算能力的瓶颈。 分片(Sharding)成为扩展Redis的关键策略&#xff0c;它将数据分散到多个Redis节点上&#xff0c;每个节点负责整个数据集的一个子集。 本文将分享5种Redis分片策略。 1. 取模分片(M…...

muduo库TcpServer模块详解

Muduo库核心模块——TcpServer Muduo库的TcpServer模块是一个基于Reactor模式的高性能TCP服务端实现&#xff0c;负责管理监听端口、接受新连接、分发IO事件及处理连接生命周期。 一、核心组件与职责 Acceptor 监听指定端口&#xff0c;接受新连接&#xff0c;通过epoll监听l…...

Java 代码生成工具:如何快速构建项目骨架?

Java 代码生成工具&#xff1a;如何快速构建项目骨架&#xff1f; 在 Java 项目开发过程中&#xff0c;构建项目骨架是一项繁琐但又基础重要的工作。幸运的是&#xff0c;Java 领域有许多代码生成工具可以帮助我们快速完成这一任务&#xff0c;大大提高开发效率。 一、代码生…...

Nginx核心服务

一&#xff0e;正向代理 正向代理&#xff08;Forward Proxy&#xff09;‌是一种位于客户端和原始服务器之间的代理服务器&#xff0c;其主要作用是将客户端的请求转发给目标服务器&#xff0c;并将响应返回给客户端 Nginx 的 正向代理 充当客户端的“中间人”&#xff0c;代…...

第22天-Python ttkbootstrap 界面美化指南

环境安装 pip install ttkbootstrap 示例1:基础主题切换器 import ttkbootstrap as ttk from ttkbootstrap.constants import *def create_theme_switcher():root = ttk.Window(title="主题切换器", themename="cosmo")def change_theme():selected = t…...

Kubernetes控制平面组件:Kubelet详解(七):容器网络接口 CNI

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…...

web应用技术第6次课---Apifox的使用

Apifox - API 文档、调试、Mock、测试一体化协作平台。拥有接口文档管理、接口调试、Mock、自动化测试等功能&#xff0c;接口开发、测试、联调效率&#xff0c;提升 10 倍。最好用的接口文档管理工具&#xff0c;接口自动化测试工具。 第一个问题&#xff1a;为什么需要用Apif…...

Flutter与Kotlin Multiplatform(KMP)深度对比及鸿蒙生态适配解析

Flutter 与 Kotlin Multiplatform&#xff08;KMP&#xff09;深度对比及鸿蒙生态适配解析 在跨平台开发领域&#xff0c;Flutter 与 Kotlin Multiplatform&#xff08;KMP&#xff09;代表了两种不同的技术路线&#xff1a;前者以 “统一 UI 体验” 为核心&#xff0c;后者以…...

Predict Podcast Listening Time-(回归+特征工程+xgb)

Predict Podcast Listening Time 题意&#xff1a; 给你每个播客的信息&#xff0c;让你预测观众的聆听时间。 数据处理&#xff1a; 1.构造新特征收听效率进行分组 2.对数据异常处理 3.对时间情绪等进行数值编码 4.求某特征值求多项式特征 5.生成特征组合 6.交叉验证并enc…...

Redis队列与Pub/Sub方案全解析:原理、对比与实战性能测试

一、为什么选择Redis实现消息队列&#xff1f; Redis凭借其内存级操作&#xff08;微秒级响应&#xff09;、丰富的数据结构以及持久化能力&#xff0c;成为构建高性能消息队列的热门选择。相比传统消息队列&#xff08;如Kafka/RabbitMQ&#xff09;&#xff0c;Redis在以下场…...

深度估计中为什么需要已知相机基线(known camera baseline)?

在计算机视觉和立体视觉的上下文中&#xff0c;“已知相机基线”&#xff08;known camera baseline&#xff09;的解释 1. 相机基线的定义 相机基线是指两个相机中心之间的距离。在立体视觉系统中&#xff0c;通常有两个相机&#xff08;或一个相机在不同位置拍摄两张图像&a…...

显卡、Cuda和pytorch兼容问题

这里写目录标题 驱动与CUDA版本兼容性问题1. **驱动与CUDA版本兼容性问题**2. **任务特性与硬件适配差异**3. **优化策略与框架配置差异**4. **散热与功耗限制**5. **数据传输与CPU瓶颈**排查建议总结 查询PyTorch中实际使用的CUDA版本**1. 查询PyTorch中实际使用的CUDA版本***…...

SseEmitter是什么

SseEmitter 是 Spring Framework 中用于实现 Server-Sent Events (SSE) 的一个类。SSE 是一种允许服务器向客户端推送实时更新的技术&#xff0c;特别适合需要从服务器到客户端的单向消息传递场景&#xff0c;如股票价格更新、社交媒体的新消息通知等。 Server-Sent Events (S…...

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市分析 OBOO鸥柏品牌推出的AI数字人触摸屏查询触控人脸识别语音交互一体机&#xff0c;是其在智能交互设备领域的又一创新产品。该一体机整合了触摸屏查询、AI人脸识别、AI声源定位语音麦克风&#xff0c;触控交互以…...

第5天-python饼图绘制

一、基础饼图绘制(Matplotlib) 1. 环境准备 python 复制 下载 pip install matplotlib numpy 2. 基础饼图代码 python 复制 下载 import matplotlib.pyplot as plt# 数据准备 labels = [1, 2, 3, 4] sizes = [30, 25, 15, 30] # 各部分占比(总和建议100) colors…...

2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛) 解题报告 | 珂学家

前言 题解 2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)。 vp了下&#xff0c;题目挺好的&#xff0c;难度也适中&#xff0c;但是彻底红温了。 第二题&#xff0c;题意不是那么清晰&#xff0c; M i n ( K 1 , K 2 ) Min(K_1, K_2) Min(K1​,K2​)容易求&#x…...

LabVIEW风机状态实时监测

在当今电子设备高度集成化的时代&#xff0c;设备散热成为关键问题。许多大型设备机箱常采用多个风机协同散热&#xff0c;确保系统稳定运行。一旦风机出现故障&#xff0c;若不能及时察觉&#xff0c;可能导致设备损坏&#xff0c;造成巨大损失。为满足对机箱内风机状态实时监…...

十一、面向对象底层逻辑-Dubbo过滤器Filter接口

一、引言&#xff1a;分布式系统中的可观测性与治理基石 在分布式服务调用链路中&#xff0c;如何在服务调用前后植入通用逻辑&#xff08;如日志记录、权限校验、性能监控等&#xff09;&#xff0c;是构建可观测、可治理系统的关键需求。Dubbo通过Filter接口实现了面向切面编…...

双检锁(Double-Checked Locking)单例模式

在项目中使用双检锁&#xff08;Double-Checked Locking&#xff09;单例模式来管理 JSON 格式化处理对象&#xff08;如 ObjectMapper 在 Jackson 库中&#xff0c;或 JsonParser 在 Gson 库中&#xff09;是一种常见的做法。这种模式确保了对象只被创建一次&#xff0c;同时在…...

linux安装nginx和前端部署vue项目

1、打包前端项目 npm run build 执行完后会在根目录下生成一个dist文件夹&#xff0c;这个dist文件夹就是我们后面要部署到nginx的东西。 2、将dist文件夹上传到服务器中 自己建一个目录&#xff0c;上传即可&#xff08;尽量不要在root目录下&#xff0c;可能涉及权限问题…...

打破次元壁,VR 气象站开启气象学习新姿势​

在教育领域&#xff0c;VR 气象站同样发挥着巨大的作用&#xff0c;为气象教学带来了全新的模式&#xff0c;打破了传统教学的次元壁&#xff0c;让学生们以全新的姿势学习气象知识。​ 在传统的气象教学中&#xff0c;学生们主要通过课本、图片和老师的讲解来学习气象知识。这…...

软件设计师“数据流图”真题考点分析——求三连

数据流图考点分析 1. 考点分值占比与趋势分析 综合知识题分值统计表 年份考题数量分值分值占比考察重点2018111.33%数据流图基本元素2019222.67%数据流图绘制原则2020111.33%数据流图与控制流图的区别2021334.00%数据字典与数据流图的关系2022222.67%分层数据流图的分解原则…...

基于R语言的贝叶斯网络模型实践技术应用:开启科研新视角

在现代科研领域&#xff0c;变量间的因果关系推断是生态学、环境科学、医学等多学科研究的核心问题。然而&#xff0c;传统的统计学方法往往只能揭示变量间的相关关系&#xff0c;而非因果关系。贝叶斯网络作为一种结合图论与统计学理论的新型模型&#xff0c;不仅能够统合多种…...

用 VS Code / PyCharm 编写你的第一个 Python 程序

用ChatGPT做软件测试 编写你的第一个 Python 程序——不只是“Hello, World”&#xff0c;而是构建认知、习惯与未来的起点 “第一行代码&#xff0c;是一个开发者认知世界的方式。” 编程的入门&#xff0c;不只是运行一个字符串输出&#xff0c;更是开始用计算机思维来理解、…...

【Git】远程操作

Git 是一个分布式版本控制系统 可以简单理解为&#xff0c;每个人的电脑上都是一个完整的版本库&#xff0c;这样在工作时&#xff0c;就不需要联网 了&#xff0c;因为版本库就在自己的电脑上。 因此&#xff0c; 多个人协作的方式&#xff0c;譬如说甲在自己的电脑上改了文件…...