lightning mdb 源代码分析(1)

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

本系列文章将尝试从如下几个方面进行分析。数据库

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

等几个方面进行分析。后端

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

其具有管理简单、开发简单等特色。管理简单是由于其设计中去掉了数据库级缓存,开发简单是兼容bdb开发接口,无需担忧数据损坏、空间膨胀、死锁等数据结构

问题。多线程

其系统基本架构为:架构

image

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

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

image

2. mdb_envinfo

image

 

首先关键的是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

image

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

image

page描述了不一样页面的头。不论是树中的root、仍是branch、leaf页面,都是用它描述。

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

将页面关联起来。

重要成员:

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

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

5.MDB_NODE

image

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

重要成员包括:

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

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

mn_data:数据指针

6. MDB_DB

image

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

7. MDB_TXN

image

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

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

事务的操做方式与其余数据库相似,嵌套事务必须匹配。

其重要的成员包括:

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

mt_next_pgno: 未分配的页面id

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

8. MDB_Cursor

image

游标对象是进行全部数据库操做的对象,读写都是基于游标进行。进行读写操做时,首先须要根据条件

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

其重要成员有:

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

mc_top: 最上层页面id

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

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

mc_ki:  全部打开页面的索引

 

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

其在lmdb中的使用方式

相关文章
相关标签/搜索