本博文系列前面已经探讨了LMDB的系统架构、MMAP映射、B-Tree操作等部分,本文将尝试描述LMDB中的事务控制的实现。

事务的基本特征:

事务是恢复和并发控制的基本单位。它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。

事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

LMDB中的实现基本思路:

Atom(A):LMDB中通过txn数据结构和cursor数据结构的控制,通过将脏页列表放入dirtylist中,当txn进行提交时再一次性统一刷新到磁盘

中或者abort时都不提交保证事务要不全成功、要不全失败。对于长事务,若页面spill到磁盘,因为COW技术,这些页面未与整棵B-Tree的root

page产生关联,因此后续的事务还是不能访问到这些页面,同样保证了事务的原子性。

其数据就是一致的,不存在因为多线程同时写数据导致数据产生错误的情况。

Isolation(I):事务隔离通过锁控制(MUTEX),LMDB支持的锁互斥是进程级别/线程级别,支持的隔离方式为锁表支持,读读之间不锁,写等待读完成之后开始,

读等待写完成后开始

Duration(D):LMDB中,没有使用WAL、undo/redo log等技术来保证系统崩溃时数据库的可用性,其保证数据持续可用的技术是COW技术和只有一线程写技术。

假如LMDB或者系统崩溃时,只有读操作,那么数据本来就没有发生变化,因此数据将不可能遭到破坏。假如崩溃时,有一个线程在进行写操作,则只需要判断最后的

页面号与成功提交到数据库中的页面号是否一致,若不一致则说明写操作没有完成,则最后一个事务写失败,数据在最后一个成功的页面前的是正确的,后续的属于

崩溃事务的,不能用,这样就保证了数据只要序列化到磁盘则一定可用,要不其就是还没有遵循ACI原则序列化到磁盘

顺便说一句,因为MMAP技术、只一个写线程的实现方案,所以数据库进行备份时特别简单,只要定期在线热备整个数据库即可完成。同时恢复也将比较快。当然由于

其使用了重用旧页技术,LMDB在恢复时只能恢复到最新状态,不能恢复到任意时刻。

实现方法:

LMDB支持嵌套事务,不期望在子事务完成之前父事务有任何读写操作,这样的话可以避免父子事务之间的数据不一致。

LMDB不支持跨线程事务,一个事务只能属于一个线程,一个线程在任一时刻只能持有一个事务。

mdb_txn_begin:

开启一个事务,根据是否传入父事务判断是否为子事务,根据传入参数判断是否为只读事务。嵌套事务支持只支持一个子事务,且子事务为写事务父事务也必须为写事务,

而且数据库不能为mmap可写方式。事务开启流程:分配内存,设置变量,若为子事务,设置父子相关关联变量并shadow父亲所有cursor以减少IO读取。否则调用renew0完成

最终的事务开启工作。

mdb_txn_abort:

放弃一个事务,有子事务则先放弃子事务,然后调用reset0真正执行结束操作。
mdb_txn_commit:

提交一个事务,有子事务则先提交子事务,若为只读事务,则关闭所有打开的数据库句柄并保持打开状态,然后放弃事务即可,若为可写事务,确定事务状态是否正确,若为error

状态,不可以提交,若不是则根据是否存在父事务进行处理,没有父事务则首先更新数据库的root节点,然后保存可重用空间到freedb以便空间重用,并释放midl空间之后,进行

页面刷新,同步相关环境变量之后释放内存,最后释放写锁,至此没有父事务情况提交完成。若有父事务,则其进行将midl列表与父事务的midl合并,cursor同样合并到父事务中进行

最终关闭,将dirtylist合并到父事务中,相关合并和本事务的变量内存释放完毕之后,子事务提交成功,即子事务主要完成内存释放,其他动作如磁盘刷新等都合并至父事务中一次性完成。

mdb_txn_reset:

放弃一个事务,但是保留句柄,仅对只读事务有效,同样调用reset0进行真正事务结束操作。
mdb_txn_reset0 :

放弃事务的公共代码.首先关闭事务中打开的数据库句柄。若是只读事务,设置事务相关变量即可,若为可写事务,需要关闭所有游标,然后释放midl空间,最后释放写锁。至此事务

关闭完毕。
mdb_txn_renew:

重用一个只读事务句柄,避免一次内存分配,检查是否有严重错误,若有失败,没有的话调用renew0完成。
mdb_txn_renew0:

renew0是renew和begin的公共代码。若是写事务,申请进程间互斥锁,若是读事务,首先检查本线程是否已经有读事务,有不支持返回错误,没有的话,开始申请读表互斥锁,

成功后将线程id记录到读表里面,然后立刻释放读表锁。然后再次确认线程中确有事务。事务(读写)申请成功后,将env的meta页面根据txnid进行切换,轮流使用。

最后再次设定些变量后通知调用者申请成功。
mdb_txn_env:

返回事务关联的env对象

上文解释了LMDB实现事务控制的方式和主要接口方法的基本流程,若实现类似关系型数据库的细粒度事务,则需要更细粒度的锁以及复杂的页面等待队列机制等以保证行锁或表锁

的正确性并最终实现事务控制机制,且在数据库应用时有可能陷入死锁状态,而在LMDB当中,读写锁分开,且进程崩溃时,系统会释放相关内核变量,从而保证要不进程正常,

锁成功释放,要不进程崩溃,系统释放锁,因此数据库永远不会陷入死锁状态,不过若事务在等待写锁,有可能等待较长时间。

希望各位能积极批评指正以及转载。

lightning mdb 源代码分析(5)-事务控制的更多相关文章

  1. lightning mdb 源代码分析(1)

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

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

    本博文将描述MVCC和cow技术以及LMDB中如何使用以及实现这两种技术. COW(Copy On Write): COW技术背后的思想是拖延技术,基本方法是假如有多个调用者需要访问的资源,在其初始化 ...

  3. lightning mdb 源代码分析(2)

    本系列前一篇已经分析了lightningmdb的整体架构和主要的数据结构.本文将介绍一下MMAP原理以及lmdb中如何使用它. 1. Memory Map原理 内存映射文件与虚拟内存有些类似,通过内存 ...

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

    本系列前两章已经描述了系统架构以及系统构建的基础内存映射,本章将详细描述lmdb的核心,外存B+Tree的操作.本文将从基本原理.内存操作方式.外存操作方式以及LMDB中的相关函数等几方面描述LMDB ...

  5. [Android]Fragment源代码分析(三) 事务

    Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = thi ...

  6. cocos2d-x 源代码分析 : control 源代码分析 ( 控制类组件 controlButton)

    源代码版本号来自3.1rc 转载请注明 cocos2d-x源代码分析总文件夹 http://blog.csdn.net/u011225840/article/details/31743129 1.继承 ...

  7. Fragment事务管理源代码分析

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/53132952 本文出自: [HansChen的博客] 概述 在Fragment使用中 ...

  8. spring事务:事务控制方式,使用AOP控制事务,七种事务传播行为,声明事务,模板对象,模板对象原理分析

    知识点梳理 课堂讲义 1)事务回顾 1.1)什么是事务-视频01 事务可以看做是一次大的活动,它由不同的小活动组成,这些活动要么全部成功,要么全部失败. 1.2)事务的作用 事务特征(ACID) 原子 ...

  9. Hadoop源代码分析

    http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...

随机推荐

  1. cas单点注销失败Error Sending message to url endpoint

    最近在做cas单点登录时,由于是单点登录.必然会涉及到单点注销,然而在做单点注销时由于对cas注销机制不了解加之测试条件所致,所有测试都是在本机下完成(机器性能较低,没用虚拟机):导致折腾了很久.网上 ...

  2. 分享一个Cnblogs简易APP

    最近在学习Android app的开发,俗话说万事开头难,本人也不例外.计算机编程是属于一门要求动手能力和动脑能力都很强的学科,相信很多人都会有这样的经历,看得懂不去用,过不了几天也就忘记了.因而,在 ...

  3. kettle使用log4j管理输出日志

    在使用kettle进行数据分析和清洗时日志非常多而且杂乱,使用原有的日志有时找不到异常的位置,有时日志不够详细,说简单一点就是日志不是我们想要的.因而对kettle日志进行相应的管理就想得尤为重要了. ...

  4. Android studio 添加依赖

    以前添加依赖总是到github上下载源码,再添加源码到module的依赖当中,其实在studio中,应该使用maven库. 比如在github上看到了sliding-menu这个项目,就应该到mave ...

  5. codeforces B. The Fibonacci Segment 解题报告

    题目链接:http://codeforces.com/problemset/problem/365/B 题目意思:简单来说,就是要找出最长的斐波纳契长度. 解决的方法不难,但是要注意更新左区间和右区间 ...

  6. poj 2013 Symmetric Order 解题报告

    题目链接:http://poj.org/problem?id=2013 设长度非递减的字串序列为s[1]...s[n].设计递归子程序print(n),其中n为字串序号,每分析1个字串,n=n-1. ...

  7. eclipse静态部署tomcat

  8. Liz Murray成功故事的偶然与必然(转)

    偶尔,我看到了一部电影:Homeless to Harvard (风雨哈佛路) 说句老实话,她( Liz Murray 莉丝·默里 )的经历确实让人钦佩和学习! 下面我看到他人写的有这本电影的评论,觉 ...

  9. 修改iptables防火墙规则解决vsftp登录后不显示文件目录的问题

    如果设置防火墙开端口可能只是常用的几个端口,这样很可能导vsftpd在被动模式时无法启动随机端口,从而造成客户端的FTP无法列出目录这样胡问题.解决方式很简单,给 vsftpd增加随机端口范围,然后把 ...

  10. MVC学习笔记---MVC生命周期及管道

    ASP.NET和ASP.NET MVC的HttpApplication请求处理管道有共同的部分和不同之处,本系列将体验ASP.NET MVC请求处理管道生命周期的19个关键环节. ①以IIS6.0为例 ...