《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》-第三篇:LMDB 深度解析

文章目录

  • [《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》](#《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》)
  • [第三篇:LMDB 深度解析](#第三篇:LMDB 深度解析)
  • [第一章 LMDB介绍](#第一章 LMDB介绍)
    • [1.1 什么是LMDB](#1.1 什么是LMDB)
  • [1.2 为什么 OpenLDAP 开发 LMDB](#1.2 为什么 OpenLDAP 开发 LMDB)
  • [1.3 LMDB设计目标](#1.3 LMDB设计目标)
  • [第二章 LMDB核心特点](#第二章 LMDB核心特点)
  • [2.1 Memory Mapping](#2.1 Memory Mapping)
  • [2.2 Zero Copy](#2.2 Zero Copy)
  • [2.3 ACID事务](#2.3 ACID事务)
    • [Atomicity 原子性](#Atomicity 原子性)
    • [Consistency 一致性](#Consistency 一致性)
    • [Isolation 隔离性](#Isolation 隔离性)
    • [Durability 持久性](#Durability 持久性)
  • [2.4 MVCC](#2.4 MVCC)
  • [2.5 Copy-On-Write](#2.5 Copy-On-Write)
  • [2.6 为什么LMDB不用WAL](#2.6 为什么LMDB不用WAL)
  • [第三章 LMDB整体架构](#第三章 LMDB整体架构)
  • LMDB内部结构:
  • [第四章 LMDB文件结构深入分析](#第四章 LMDB文件结构深入分析)
  • [4.1 data.mdb整体布局](#4.1 data.mdb整体布局)
  • [4.2 Meta Page](#4.2 Meta Page)
    • [为什么需要两个Meta Page?](#为什么需要两个Meta Page?)
  • [4.3 Page类型](#4.3 Page类型)
    • [1. Branch Page](#1. Branch Page)
    • [2. Leaf Page](#2. Leaf Page)
    • [3. Overflow Page](#3. Overflow Page)
    • [4. Free Page](#4. Free Page)
  • [第五章 mmap原理](#第五章 mmap原理)
  • [5.1 传统读取方式](#5.1 传统读取方式)
  • [5.2 mmap读取方式](#5.2 mmap读取方式)
  • [5.3 为什么读取速度快?](#5.3 为什么读取速度快?)
  • [第六章 LMDB中的B+Tree索引](#第六章 LMDB中的B+Tree索引)
  • [6.1 为什么使用B+Tree?](#6.1 为什么使用B+Tree?)
  • [6.2 LMDB B+Tree结构](#6.2 LMDB B+Tree结构)
    • [Root Page](#Root Page)
    • [Branch Page](#Branch Page)
    • [Leaf Page](#Leaf Page)
  • [6.3 为什么没有独立索引?](#6.3 为什么没有独立索引?)
  • [6.4 B+Tree查找过程](#6.4 B+Tree查找过程)
  • [6.5 为什么LMDB遍历很快?](#6.5 为什么LMDB遍历很快?)
  • [第七章 LMDB与传统B+Tree数据库区别](#第七章 LMDB与传统B+Tree数据库区别)
  • LMDB核心思想总结
  • [第三部分:Copy-On-Write、MVCC、Overflow Page](#第三部分:Copy-On-Write、MVCC、Overflow Page)
  • [第八章 Copy-On-Write(写时复制)](#第八章 Copy-On-Write(写时复制))
  • [8.1 什么是 Copy-On-Write](#8.1 什么是 Copy-On-Write)
  • [8.2 LMDB写事务流程](#8.2 LMDB写事务流程)
  • [8.3 为什么Copy-On-Write不需要WAL?](#8.3 为什么Copy-On-Write不需要WAL?)
  • [第九章 MVCC机制](#第九章 MVCC机制)
  • [9.1 为什么需要MVCC?](#9.1 为什么需要MVCC?)
  • [9.2 Reader Snapshot](#9.2 Reader Snapshot)
  • [9.3 多Reader并发](#9.3 多Reader并发)
  • [9.4 为什么一个Writer?](#9.4 为什么一个Writer?)
  • [9.5 写事务冲突](#9.5 写事务冲突)
  • [第十章 Overflow Page](#第十章 Overflow Page)
  • [10.1 普通数据结构](#10.1 普通数据结构)
  • [10.2 大Value存储](#10.2 大Value存储)
  • [10.3 Overflow Page特点](#10.3 Overflow Page特点)
  • [10.4 为什么不用拆成多个Key?](#10.4 为什么不用拆成多个Key?)
  • [10.5 视觉行业典型应用](#10.5 视觉行业典型应用)
  • [第十一章 Free List机制](#第十一章 Free List机制)
  • [第十二章 LMDB事务模型总结](#第十二章 LMDB事务模型总结)
  • LMDB核心优势总结
  • [第四部分:LMDB Cursor与源码分析](#第四部分:LMDB Cursor与源码分析)

《现代 Key-Value 数据库原理:从 B+Tree 到 LSM Tree》

第三篇:LMDB 深度解析


第一章 LMDB介绍

1.1 什么是LMDB

LMDB(Lightning Memory-Mapped Database)是一款高性能嵌入式 Key-Value 数据库。

官方全称:

复制代码
Lightning Memory-Mapped Database

中文可以理解为:

基于内存映射技术的高速轻量级数据库。

LMDB 最初由 OpenLDAP Project 团队开发,用于替代传统 Berkeley DB。

它被大量应用于:

  • LDAP服务器
  • AI训练数据集
  • 图像数据库
  • 嵌入式系统
  • 高性能缓存系统

典型使用场景:

复制代码
Key

↓

Value


image_001

↓

JPEG二进制数据


pointcloud_001

↓

PLY/LAS数据


tensor_001

↓

float数组

1.2 为什么 OpenLDAP 开发 LMDB

在早期 LDAP 系统中,数据库主要使用:

复制代码
Berkeley DB

但是随着数据规模增长,出现一些问题。

例如:

问题1:复杂锁机制

传统数据库:

复制代码
Reader

   |
Lock

   |

Writer

大量读请求会竞争锁。


问题2:缓存重复

传统数据库:

复制代码
Disk

↓

Database Cache

↓

Application Buffer

↓

User Memory

一次读取:

数据可能复制多次。

例如:

复制代码
磁盘数据

100MB


↓

数据库缓存

100MB


↓

应用缓存

100MB


↓

程序对象

100MB

最终:

复制代码
400MB内存

保存同一份数据。


问题3:事务恢复复杂

传统数据库:

复制代码
Write Data

↓

WAL日志

↓

Flush

↓

Commit

需要:

  • 日志管理
  • 崩溃恢复
  • checkpoint

维护成本高。


1.3 LMDB设计目标

LMDB设计目标非常明确:

目标1:极致读取性能

利用:

复制代码
mmap

直接映射文件。

让:

复制代码
Disk

↓

Virtual Memory

↓

Application

减少数据复制。


目标2:简单可靠事务

采用:

复制代码
MVCC

+

Copy-On-Write

实现:

  • 多读
  • 单写
  • 无锁读取

目标3:零维护

LMDB没有:

  • 后台线程
  • Cache管理
  • Compaction
  • WAL

数据库就是:

复制代码
一个文件

第二章 LMDB核心特点

LMDB主要由以下几个技术组成:

复制代码
Memory Mapping

Zero Copy

B+Tree

MVCC

Copy-On-Write

ACID Transaction

2.1 Memory Mapping

核心技术:

复制代码
mmap()

传统数据库:

复制代码
Application

    |
read()

    |

Kernel Buffer

    |

Disk

数据路径:

复制代码
Disk

↓

Kernel Page Cache

↓

Application Buffer

需要复制。


LMDB:

复制代码
Database File


        |
        |
       mmap


        ↓


Virtual Memory


        ↓


Application

应用直接访问文件映射区域。

例如:

数据库:

复制代码
data.mdb


0x0000

Page0


0x1000

Page1


0x2000

Page2

映射后:

复制代码
虚拟地址:

0x80000000


↓

Page0


0x80001000


↓

Page1

访问:

cpp 复制代码
value = ptr[offset];

实际上访问:

复制代码
磁盘文件页

2.2 Zero Copy

传统数据库:

读取:

复制代码
Disk

↓

Kernel Buffer

↓

Database Buffer

↓

Application Memory

三次复制。

LMDB:

复制代码
Disk

↓

Memory Mapping

↓

Application Pointer

数据直接暴露。

例如:

保存图片:

复制代码
image.jpg

10MB

传统:

复制代码
read()

↓

malloc(10MB)

↓

copy

LMDB:

复制代码
const void* ptr;

mdb_get()

↓

返回地址

直接读取。


2.3 ACID事务

LMDB支持完整 ACID:


Atomicity 原子性

事务:

复制代码
BEGIN


修改A

修改B


COMMIT

如果失败:

复制代码
全部取消

Consistency 一致性

B+Tree结构始终正确。


Isolation 隔离性

多个Reader:

看到:

复制代码
自己的Snapshot

Durability 持久性

提交后:

数据最终写入磁盘。


2.4 MVCC

Multi Version Concurrency Control。

多版本并发控制。

核心思想:

不修改旧数据,而是创建新版本。

例如:

原始数据:

复制代码
Page 10


key=A

value=100

修改:

复制代码
A=200

不是覆盖:

而是:

复制代码
Page 10

A=100


Page 20

A=200

然后:

切换Root。


2.5 Copy-On-Write

LMDB最大特色。

传统数据库:

复制代码
修改Page


↓

覆盖旧Page


↓

写WAL

LMDB:

复制代码
旧Page

        不动


复制


↓

新Page


↓

修改


↓

更新Root

例如:

原始:

复制代码
          Root


            |

          Page1


            |

          Data=A

修改:

创建:

复制代码
          New Root


             |

          New Page1


             |

          Data=B

旧数据:

仍然存在。


2.6 为什么LMDB不用WAL

传统数据库:

复制代码
修改数据

↓

写日志

↓

修改数据页

因为:

如果崩溃:

根据日志恢复。


LMDB:

由于:

复制代码
Copy-On-Write

所以:

旧数据永远存在。

提交过程:

复制代码
写新Page


↓

flush


↓

修改Root Pointer

如果中途崩溃:

旧Root仍然有效。

恢复:

直接使用旧版本。

因此:

不需要:

复制代码
Write Ahead Log

第三章 LMDB整体架构

LMDB数据库目录:

复制代码
mydb/


├── data.mdb

└── lock.mdb

其中:

data.mdb

真正数据文件。

包含:

复制代码
Meta Page

B+Tree Pages

Data Pages

Free Pages

lock.mdb

用于:

复制代码
Reader Table

Lock Information

Transaction State

记录:

当前:

复制代码
Reader数量

Reader ID

LMDB内部结构:

复制代码
data.mdb


+----------------+

| Meta Page 0    |

+----------------+

| Meta Page 1    |

+----------------+

| Root Page      |

+----------------+

| Branch Pages   |

+----------------+

| Leaf Pages     |

+----------------+

| Overflow Pages |

+----------------+

| Free Pages     |

+----------------+

第二部分:文件结构、mmap原理、B+Tree索引


第四章 LMDB文件结构深入分析

LMDB整个数据库非常简单。

一个数据库环境:

复制代码
my_database/

├── data.mdb

└── lock.mdb

其中:

  • data.mdb:存储全部数据
  • lock.mdb:管理事务和读写同步

LMDB没有:

复制代码
日志文件

缓存文件

索引文件

临时文件

所有内容都在:

复制代码
data.mdb

中。


4.1 data.mdb整体布局

LMDB的数据文件本质:

一个由固定大小 Page 组成的大文件。

默认:

复制代码
Page Size = 4096 bytes

也就是:

复制代码
4KB/Page

结构:

复制代码
data.mdb


+----------------+
| Meta Page 0    |
+----------------+
| Meta Page 1    |
+----------------+
| Branch Page    |
+----------------+
| Branch Page    |
+----------------+
| Leaf Page      |
+----------------+
| Leaf Page      |
+----------------+
| Overflow Page  |
+----------------+
| Free Page      |
+----------------+

为什么使用Page?

因为操作系统:

复制代码
Virtual Memory

↓

Page

↓

Disk Block

天然以Page为单位管理。

LMDB直接利用操作系统:

复制代码
OS Page Cache

而不是自己实现缓存。


4.2 Meta Page

LMDB最重要的结构之一:

复制代码
Meta Page

文件开始位置:

复制代码
Page 0

Page 1

两个Meta Page。

例如:

复制代码
data.mdb


Page0
+----------------+
| Meta Version 1 |
| Root=100       |
+----------------+


Page1
+----------------+
| Meta Version 2 |
| Root=200       |
+----------------+

为什么需要两个Meta Page?

因为事务提交不能直接覆盖。

假设:

当前:

复制代码
Meta0:

Root Page = 100

进行修改:

创建:

复制代码
New Root = 200

提交:

步骤:

复制代码
1.

写入新的数据Page


2.

写新的Meta Page


3.

切换Meta指针

如果崩溃:

情况:

复制代码
New Page 已写入

Meta 未更新

启动:

发现:

复制代码
Meta0有效

继续使用旧版本。


如果:

复制代码
Meta1更新成功

启动:

读取:

复制代码
最新Meta

即可。


所以:

两个Meta Page实现:

复制代码
Crash Recovery

4.3 Page类型

LMDB主要有几种Page。

1. Branch Page

也叫:

复制代码
Internal Node

用于:

B+Tree索引。

保存:

复制代码
Key

Child Page Number

例如:

复制代码
          Root


       Branch Page


   10       50       90


   |        |        |


 Leaf     Leaf     Leaf

2. Leaf Page

真正保存数据。

例如:

复制代码
Leaf Page


+----------------+
| key=a          |
| value=100      |
+----------------+

| key=b          |
| value=200      |
+----------------+

3. Overflow Page

保存超大Value。

例如:

普通Page:

复制代码
4KB

但是:

Value:

复制代码
20KB

无法保存。

需要:

复制代码
Page100

+
Page101

+
Page102

+
Page103

+
Page104

连续Page。


4. Free Page

释放后的Page。

例如:

删除:

复制代码
key=A

旧Page不会立即覆盖。

进入:

复制代码
Free List

以后事务重新利用。


第五章 mmap原理

LMDB性能核心:

复制代码
Memory Mapping

5.1 传统读取方式

例如:

读取:

复制代码
data.db

100MB数据。

传统:

复制代码
Application


   read()


      ↓


Kernel Buffer


      ↓


Disk

数据复制:

第一次:

复制代码
Disk
 ↓
Kernel Buffer

第二次:

复制代码
Kernel Buffer
 ↓
Application Buffer

产生:

复制代码
Copy

5.2 mmap读取方式

LMDB:

调用:

cpp 复制代码
mmap()

建立:

复制代码
文件

↓

虚拟地址空间

结构:

复制代码
        Disk


     data.mdb


          |
          |
        mmap


          |
          |

 Virtual Memory


          |
          |

      Application

例如:

文件:

复制代码
data.mdb


offset 4096

Page1

映射:

复制代码
0x10000000


↓

Page1

程序:

cpp 复制代码
char* ptr;

ptr[10];

CPU访问:

复制代码
虚拟地址

↓

MMU

↓

Page Table

↓

物理页

↓

磁盘缓存

5.3 为什么读取速度快?

原因:

原因1:减少复制

传统:

复制代码
Disk

↓

Kernel

↓

DB

↓

Application

LMDB:

复制代码
Disk

↓

Virtual Memory

↓

Application

原因2:利用OS Page Cache

Linux/Windows已经维护:

复制代码
热点数据

LMDB不用再次实现:

复制代码
LRU Cache

原因3:CPU缓存友好

B+Tree节点:

连续Page。

CPU读取:

复制代码
Cache Line

↓

Memory

效率高。


第六章 LMDB中的B+Tree索引

LMDB虽然叫:

Key-Value数据库。

但是底层:

不是Hash。

而是:

复制代码
B+Tree

6.1 为什么使用B+Tree?

因为数据库主要操作:

复制代码
查询

范围查询

排序遍历

例如:

查询:

复制代码
key=1000

范围:

复制代码
1000 ~ 2000

B+Tree非常适合。


6.2 LMDB B+Tree结构

结构:

复制代码
                 Root


                  |

           Branch Page


          /     |      \


       Page10 Page20 Page30


          |      |       |


       Leaf   Leaf    Leaf

Root Page

保存:

最高层索引。

例如:

复制代码
A-M

N-Z

Branch Page

保存:

复制代码
Key

Child Page ID

例如:

复制代码
       Branch


A

↓

Page100


M

↓

Page200

Leaf Page

保存:

真正KV。

例如:

复制代码
Leaf Page


apple

100


banana

200


cat

300

6.3 为什么没有独立索引?

很多数据库:

例如:

MySQL InnoDB:

结构:

复制代码
Index

↓

Data

索引和数据分离。


LMDB:

数据本身就是B+Tree。

结构:

复制代码
B+Tree


Root

↓

Branch

↓

Leaf


Leaf里面就是Value

所以:

没有:

复制代码
额外Index

优势:

减少一次查找。

传统:

复制代码
Index

↓

Record

两次访问。

LMDB:

复制代码
Index + Data

一次完成

6.4 B+Tree查找过程

查询:

复制代码
key="camera001"

第一步:

Root:

复制代码
camera001

↓

找到Branch Page

第二步:

Branch:

复制代码
camera001

↓

Page 500

第三步:

Leaf:

复制代码
camera001

↓

Value

复杂度:

复制代码
O(logN)

6.5 为什么LMDB遍历很快?

因为:

B+Tree Leaf节点:

通过链表连接。

例如:

复制代码
Leaf1

↓

Leaf2

↓

Leaf3

↓

Leaf4

遍历:

复制代码
Cursor

↓

顺序读取

无需重新搜索。


第七章 LMDB与传统B+Tree数据库区别

LMDB MySQL InnoDB
索引 数据本身 独立索引
缓存 OS Page Cache Buffer Pool
日志 无WAL Redo Log
事务 Copy-On-Write Undo/Redo
并发 MVCC MVCC
写入 单Writer 多Writer
读取 极快
适合 读多写少 高并发业务

LMDB核心思想总结

LMDB不是通过:

复制代码
复杂缓存

大量线程

日志系统

获得性能。

而是:

复制代码
利用操作系统

+

B+Tree

+

Copy-On-Write

+

MVCC

达到:

极低延迟读取。


第三部分:Copy-On-Write、MVCC、Overflow Page


第八章 Copy-On-Write(写时复制)

Copy-On-Write(COW)是 LMDB 最核心的设计。

它决定了:

  • 为什么 LMDB 不需要 WAL
  • 为什么读取没有锁
  • 为什么事务回滚非常简单
  • 为什么数据库恢复速度极快

8.1 什么是 Copy-On-Write

传统数据库:

修改已有数据:

复制代码
Old Page

↓

直接覆盖

↓

New Data

例如:

原数据:

复制代码
Page 100


key=A

value=100

修改:

复制代码
A=200

传统方式:

复制代码
Page 100


key=A

value=200

问题:

如果写入过程中断电:

复制代码
Page写了一半

↓

数据损坏

所以需要:

复制代码
WAL日志

LMDB:

不会修改旧Page。

流程:

复制代码
Old Page

        保留


复制


        ↓


New Page


        ↓


修改New Page

8.2 LMDB写事务流程

假设数据库:

复制代码
              Root


                |

             Page 100


                |

             key=A

             value=100

现在执行:

cpp 复制代码
put("A",200)

第一步:开启Write Transaction

复制代码
Writer Transaction

开始

当前:

复制代码
Root

↓

Page100

第二步:复制Page

创建:

复制代码
Page200


key=A

value=100

此时:

复制代码
Old Page100

        保留


New Page200

        修改

第三步:修改新Page

复制代码
Page200


key=A

value=200

第四步:创建新的Root

旧:

复制代码
Root


↓

Page100

新:

复制代码
New Root


↓

Page200

第五步:提交

提交顺序:

复制代码
写入New Page


↓

flush磁盘


↓

更新Meta Page


↓

完成commit

最终:

复制代码
Meta


↓

New Root


↓

Page200


↓

value=200

旧版本:

复制代码
Page100


value=100

仍然存在。


8.3 为什么Copy-On-Write不需要WAL?

传统数据库:

需要恢复:

复制代码
日志

↓

重新执行修改

例如:

复制代码
Redo Log:

修改Page100

value=200

崩溃后:

重新执行。


LMDB:

恢复:

只需要找到:

复制代码
最新Meta Page

即可。

因为:

数据已经完整写入。

例如:

情况1:

复制代码
New Page写成功

Meta未更新

启动:

读取旧Meta:

复制代码
Root=Page100

结果:

旧数据。


情况2:

复制代码
New Page成功

Meta更新成功

启动:

读取:

复制代码
Root=Page200

新数据。


所以:

恢复过程:

复制代码
读取Meta Page

↓

找到Root

↓

继续运行

没有:

复制代码
日志扫描

Redo

Undo

第九章 MVCC机制

LMDB支持:

复制代码
Multi Version Concurrency Control

多版本并发控制。

核心:

Reader永远读取一个稳定的数据快照。


9.1 为什么需要MVCC?

数据库同时存在:

复制代码
Reader

Writer

例如:

线程A:

读取:

复制代码
key=A

线程B:

修改:

复制代码
key=A

如果直接覆盖:

Reader可能看到:

复制代码
半修改数据

LMDB:

使用版本。


9.2 Reader Snapshot

假设:

当前版本:

复制代码
Transaction ID = 100

Reader打开:

复制代码
Reader TXN


看到:

Version 100

此时Writer修改:

产生:

复制代码
Version 101

结构:

复制代码
Version100


Root


↓

Old Page


value=100



Version101


Root


↓

New Page


value=200

Reader:

仍然:

复制代码
读取Version100

Writer:

使用:

复制代码
Version101

两者互不影响。


9.3 多Reader并发

LMDB允许:

复制代码
Reader1

Reader2

Reader3

Reader4

...

同时读取。

例如:

复制代码
          Database


        /    |     \


 Reader1 Reader2 Reader3


Version100

因为:

Reader不修改数据。

所以:

无需锁。


9.4 为什么一个Writer?

LMDB设计:

复制代码
多个Reader

+

一个Writer

原因:

写事务涉及:

复制代码
修改Root

分配Page

更新Free List

如果多个Writer:

需要解决:

复制代码
Page冲突

Root竞争

Free List竞争

复杂度大幅增加。


因此:

LMDB采用:

复制代码
Single Writer

换取:

极低复杂度。


9.5 写事务冲突

例如:

两个线程:

复制代码
Writer A

Writer B

同时:

复制代码
修改数据库

结果:

复制代码
Writer A

获得写锁


Writer B

等待

完成:

复制代码
A Commit

↓

B开始

第十章 Overflow Page

数据库中:

Value大小是不固定的。

例如:

Key:

复制代码
image001

Value:

复制代码
JPEG图片

可能:

复制代码
5MB

普通Leaf Page:

大小:

复制代码
4KB

无法保存。

所以LMDB设计:

Overflow Page。


10.1 普通数据结构

例如:

复制代码
Key

Value

大小:

复制代码
500 Bytes

保存:

复制代码
Leaf Page


+----------------+

key

value

+----------------+

10.2 大Value存储

例如:

复制代码
Value:

20KB

Page:

复制代码
4KB

需要:

复制代码
20KB / 4KB

≈5 Pages

结构:

复制代码
Leaf Page


key=image001


overflow pointer

        |

        ↓


Page100

Page101

Page102

Page103

Page104

10.3 Overflow Page特点

连续分配:

复制代码
Page100

Page101

Page102

原因:

提高:

复制代码
顺序读取速度

10.4 为什么不用拆成多个Key?

例如:

图片:

复制代码
20MB

拆:

复制代码
image001_part1

image001_part2

...

问题:

读取:

需要:

复制代码
多次查找

多次拼接

效率低。

LMDB:

直接:

复制代码
一个Value

多个连续Page

10.5 视觉行业典型应用

例如:

工业视觉:

一张图片:

复制代码
4096×4096

16bit TIFF

≈32MB

存储:

复制代码
key:

camera001_20260807_001


value:

binary image data

LMDB:

复制代码
Leaf


key


↓

Overflow Pages


↓

Image

读取:

复制代码
一次事务

直接映射内存

第十一章 Free List机制

Copy-On-Write产生一个问题:

旧Page怎么办?

例如:

修改:

复制代码
Page100

↓

生成Page200

那么:

Page100:

已经不用。

不能马上删除。

因为:

Reader可能还在使用。


所以:

LMDB维护:

复制代码
Free List

结构:

复制代码
Free List


Page100

Page300

Page500

什么时候回收?

当:

复制代码
所有Reader

都不再使用旧版本

之后:

这些Page:

重新分配。


第十二章 LMDB事务模型总结

完整流程:

复制代码
Reader


打开事务


↓

获取Snapshot


↓

读取旧Root


↓

无锁访问

Writer:

复制代码
Begin Write


↓

Copy-On-Write


↓

生成新Page


↓

更新Root


↓

Commit


↓

新版本生效

整个系统:

复制代码
                Meta Page


                    |

                  Root


                    |

                B+Tree


                    |

              Leaf / Overflow



Reader:

读取旧版本


Writer:

创建新版本

LMDB核心优势总结

技术 作用
mmap 减少复制,提高读取
B+Tree 高效索引
Copy-On-Write 无需WAL
MVCC 读写隔离
Overflow Page 支持大Value
Free List 空间复用
Single Writer 降低复杂度

下一部分:

第四部分:LMDB Cursor与源码分析

内容:

  • Cursor为什么遍历极快
  • mdb_env结构
  • mdb_txn结构
  • mdb_cursor结构
  • mdb_page结构
  • mdb_node结构
  • 从源码角度分析一次put/get流程

见下一篇

相关推荐
范什么特西8 小时前
回答知识总结04(redis)
数据库·redis·缓存
码农颜9 小时前
5.4.1 锁分类
java·数据库·mysql
云深处@9 小时前
【数据库】MySQL 入门
数据库·学习·mysql
梦远星帆9 小时前
SQLyog社区版下载
数据库·mysql·sqlyog
科力锐品牌君11 小时前
行业龙头|科力锐全链路防勒索 + 多中心容灾方案,构筑河南翔宇医疗业务安全闭环!
网络·数据库·分布式·安全·数据安全·备份
zyplayer-doc11 小时前
zyplayer-doc企业知识库能做什么:从文档创建、权限管理到AI问答的完整能力
大数据·javascript·数据库·人工智能·pdf·word
会编程的吕洞宾13 小时前
LangChain4j Tool Calling 实战:让大模型自动查数据库发邮件,一句话搞定复杂任务
数据库·人工智能
知行合一。。。14 小时前
DeepAgents--01--Agent和OpenClaw的相关概念
android·数据库
c2385614 小时前
# Mini OJ — 项目详解文档
开发语言·数据库·c++
DFT计算杂谈14 小时前
C4T交错磁体中的超导交织序向列涨落与自旋流环涨落的选择机制
大数据·数据库·人工智能