lightning mdb 源代码分析(1)

lighting mdb(lmdb) 是一个高性能mmap kv数据库,基本介绍和文档参见symas官网,本文将尝试分析其源代码结构以理解数据库设计的关键技术。

本系列文章将尝试从以下几个方面进行分析。

  1. 系统架构(本文)
  2. MMAP映射(系列2)
  3. B+Tree操作(系列3)
  4. 事务管理(系列4)
  5. MVCC控制(系列5)

等几个方面进行分析。

lmdb是为了改进OPENLADP工程的数据缓存后端数据库(bdb)的一系列设计问题,比如多重缓存设计、锁控制、空间膨胀的问题而研发的一款数据库。

其具备管理简单、开发简单等特点。管理简单是因为其设计中去掉了数据库级缓存,开发简单是兼容bdb开发接口,无需担心数据损坏、空间膨胀、死锁等

问题。

其系统基本架构为:

设计上使用了mmap和COW技术,因此整体架构比较简单,没有其他数据库的缓存管理、日志管理、外存管理等组件。

mmap文件映射是基础,lmdb通过只读文件映射(默认)避免了因为应用程序bug导致数据库被破坏的情形。其上的

一些基础结构比如Locktables,MVCC,COW等都是实现事务控制的基础,通过这些理论基础,lmdb实现了完整的

ACI属性,D通过mmap实现。最后,系统对外提供了关于B+Tree的操作方式,利用cursor游标进行。可以进行增删改查。

B+Tree的所有变动方式与其他的实现类似,不过lmdb的实现基础是append only B+Tree,后续系列将详细解释lmdb里面的

B+Tree实现方式。

主要的系统数据结构有:

1. MDB_ENV

2. mdb_envinfo

首先关键的是env对象,environment对象代表了一个实际的物理存储文件。lmdb采取的存储方式是直接B+Tree存储,索引和值都存储在B+Tree的

页面上,对于值特别大的对象通过overflow页面解决。而非像其他存储方式,索引与数据分离。但是lmdb存储支持在同一个物理文件中存储多个B+Tree,

以及可以将某个B+Tree作为另一个B+Tree的叶子节点,即其提到的sub-database概念。这对于某些特定的应用比较有效,比如简单的层次对应数据结构的

管理和查询。

env对象中重要数据成员有:

me_dirty-list:脏页列表,是写事务已经修改过的但没有提交到物理文件中的所有页面列表。

me_free_pgs: 可用页面,可用页面用于控制MVCC导致的文件大小膨胀,可用页面是指已经没有事务使用但是已经被修改,根据MVCC原理,其已经是旧版本的页面。

对于需要查阅历史数据的数据库来说,比如说需要恢复到任意时刻的要求,所有的旧版本应该被保存,而对于只需要保持最新一致数据的数据库系统比如lmdb来说,这些

页面是可以重用的,页面重用就可以有效避免物理文件的无限增大。free_pgs为当前写事务导致的可重用页面列表。

me_metas: 元数据列表,lmdb使用两个页面作为meta页面,因此其大小为2. meta页面的一个主要作用是用于保存B+Tree的root_page指针。其内部采用COW技术,root

page指针可能会被修改,因此使用两个不同的页面进行切换保存最新页面,类似于double-buffer设计。由此可知,虽然lmdb支持一个文件中多个B+Tree,由于meta页面的

限制,其个数是有限的。

me_rmutext,me_wmutex: 锁表互斥所,lmdb可以支持多线程、多进程。多进程之间的同步访问通过系统级的互斥来达到。其mutex本身存在于系统的共享内存当中而非进程本身的内存,因此

在进行读写页面时,首先访问锁表看看对应的资源是否有别的进程、线程在进行,有的话需要根据事务规则要求进行排队等待。详细的锁使用见后文解释。

me_txn,me_txns: 目前环境中使用的事务列表,一个env对象归属于一个进程,一个进程可能有多个线程使用同一个env,每个线程可以开启一个事务,因此在一个进程级的env对象需要维护txn列表

以了解目前多少个线程及事务在进行工作。

me_flags: 标志,标志控制的数据库的许多行为,每次使用env之前必须设置,应用程序应该用一致的方式使用flags,否则数据库可能会出现不可预知的错误。

me_dbxs: 数据库对象

me_userctx: 用户数据,用户上下文数据,主要用于进行key比较时进行辅助。

envinfo对象中成员比较直白,不多啰嗦。

3. mdb_meta

meta页的更新由事务id决定,读事务不更新元数据页,写数据可能更新。

meta页面循环使用,即id为1,修改页面1,id为2,修改页面0.

其最重要的数据成员就是

mm_dbs: 数据库B+Tree根,同时保存两个,0为目前使用的可替代的root page指针,1为当前使用的主数据库。

mm_version: 当前lock文件的version,是实现MVCC的重要成员,必须设置为MDB_DATA_VERSION.

4. MDB_PAGE

page描述了不同页面的头。不管是树中的root、还是branch、leaf页面,都是用它描述。

对于overflow页面来说,只有第一页使用头进行描述,其后的连续页面不使用,仅仅使用指针

将页面关联起来。

重要成员:

mp_flags: 代表是什么类型的页面

mp_pb: overflow页数或者当前页的可用空间

5.MDB_NODE

node代表key/value对的描述,是对branch、leaf页中的数据的描述

重要成员包括:

mn_flags: 标志:是否重复、子数据库、overflow等

mn_hi.lo: 数据大小或者页码

mn_data:数据指针

6. MDB_DB

mdb_db描述了一颗单独的b+tree数,主要包含了一些相关的信息和根节点页码

7. MDB_TXN

mdb_txn描述了事务的数据结构,mdb中的事务支持嵌套事务。支持完全ACID属性,

但是只支持serializable事务隔离级别,通过同一个env对应的数据库只允许一个事务写来控制。

事务的操作方式与其他数据库类似,嵌套事务必须匹配。

其重要的成员包括:

mt_child,parent:事务嵌套父子关系

mt_next_pgno: 未分配的页面id

mt_cursor: 写事务中每个数据库中已经打开的游标。

8. MDB_Cursor

游标对象是进行所有数据库操作的对象,读写都是基于游标进行。进行读写操作时,首先需要根据条件

确定页面位置,从而获得一个游标,应用程序根据游标对象操作数据库。

其重要成员有:

mc_next: 同一个事务中关于同一个db的游标组成一个列表。next指向下一个游标

mc_top: 最上层页面id

mc_xcursor: 用于key可重复b+tree。

mc_pg: cursor打开的页面组成一个堆栈,最多32个,具体作用还有待探查。

mc_ki:  所有打开页面的索引

本文简单讲述了lmdb的整体架构以及重要的数据成员。本系列下次介绍MMAP原理以及

其在lmdb中的使用方式

时间: 2024-10-22 13:11:25

lightning mdb 源代码分析(1)的相关文章

lightning mdb 源代码分析系列(3)

本系列前两章已经描述了系统架构以及系统构建的基础内存映射,本章将详细描述lmdb的核心,外存B+Tree的操作.本文将从基本原理.内存操作方式.外存操作方式以及LMDB中的相关函数等几方面描述LMDB中关于B+Tree的使用方式. 介绍 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树 (Red-Black Tree ),B-tree/B+-tree/ B*-tree(B~Tree).前三者是典

lightning mdb 源代码分析(2)

本系列前一篇已经分析了lightningmdb的整体架构和主要的数据结构.本文将介绍一下MMAP原理以及lmdb中如何使用它. 1. Memory Map原理 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存.由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不需要由应用程

lightning mdb 源代码分析(5)-事务控制

本博文系列前面已经探讨了LMDB的系统架构.MMAP映射.B-Tree操作等部分,本文将尝试描述LMDB中的事务控制的实现. 事务的基本特征: 事务是恢复和并发控制的基本单位.它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位. 事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性. 事务应该具有4个属性:原子性.一致性.隔离性.持久性.这四个属性通常称为ACID特性. 原子性(atomicity).一个事务是一个不可分割的工作单位,事务中包括的诸操

lightning mdb 源代码分析(4)—MVCC/COW

本博文将描述MVCC和cow技术以及LMDB中如何使用以及实现这两种技术. COW(Copy On Write): COW技术背后的思想是拖延技术,基本方法是假如有多个调用者需要访问的资源,在其初始化的时候是不能区分的,即对于多个调用者来说,这资源就是一样的.这样就可以给每个 调用者一个指向资源的指针即可.这种方法一直持续到调用者需要进行修改所需要访问的资源时,在这个时候,调用者将被分配到一份真正私有的资源拷贝,这样调用者对资源的任意 改动对于其它调用者来说都是不可见的.所有的以上操作对于调用者

Java中arraylist和linkedlist源代码分析与性能比較

Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arraylist和linkedlist的性能. 2,arraylist源代码分析 Arraylist底层的数据结构是一个对象数组.有一个size的成员变量标记数组中元素的个数,例如以下图: * The array buffer into which the elements of the ArrayLis

转:RTMPDump源代码分析

0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://.也提供 Android 版本. 最近研究了一下它内部函数调用的关系. 下面列出几个主要的函数的调用关系. RTMPDump用于下载RTMP流媒体的函数Download: 用于建立网络连接(NetConnect)的函数Connect: 用于建立网络流(NetStream)的函数 rtmpdump源代码

Kafka SocketServer源代码分析

Kafka SocketServer源代码分析 标签: kafka 本文将详细分析Kafka SocketServer的相关源码. 总体设计 Kafka SocketServer是基于Java NIO来开发的,采用了Reactor的模式,其中包含了1个Acceptor负责接受客户端请求,N个Processor负责读写数据,M个Handler来处理业务逻辑.在Acceptor和Processor,Processor和Handler之间都有队列来缓冲请求. kafka.network.Accepto

pomelo源代码分析(一)

千里之行始于足下,一直说想了解pomelo,对pomelo有兴趣,但一直迟迟没有去碰,尽管对pomelo进行源代码分析,在网络上肯定不止我一个,已经有非常优秀的前辈走在前面,如http://golanger.cn/,在阅读Pomelo代码的时候,已经连载到了11篇了,在我的源代码分析參考了该博客,当然,也会添?我对pomelo的理解,借此希望能提高一下自己对node.js的了解和学习一些优秀的设计. 开发环境:win7 调试环境:webstorm5.0 node.js版本号:v0.8.21 源代

Jafka源代码分析——随笔

Kafka是一个分布式的消息中间件,可以粗略的将其划分为三部分:Producer.Broker和Consumer.其中,Producer负责产生消息并负责将消息发送给Kafka:Broker可以简单的理解为Kafka集群中的每一台机器,其负责完成消息队列的主要功能(接收消息.消息的持久化存储.为Consumer提供消息.消息清理.....):Consumer从Broker获取消息并进行后续的操作.每个broker会有一个ID标识,该标识由人工在配置文件中配置. Kafka中的消息隶属于topic