本博文将描述MVCC和cow技术以及LMDB中如何使用以及实现这两种技术。

COW(Copy On Write):

COW技术背后的思想是拖延技术,基本方法是假如有多个调用者需要访问的资源,在其初始化的时候是不能区分的,即对于多个调用者来说,这资源就是一样的。这样就可以给每个

调用者一个指向资源的指针即可。这种方法一直持续到调用者需要进行修改所需要访问的资源时,在这个时候,调用者将被分配到一份真正私有的资源拷贝,这样调用者对资源的任意

改动对于其它调用者来说都是不可见的。所有的以上操作对于调用者来说是透明的,这种方法最大的好处就是假如调用者不修改资源,私有拷贝就不会被创建。因此这种技术对于读大于

写的应用场景来说特别合适,比如说虚拟内存与分页、数据库、string对象等等,都使用此技术以提升系统性能。

MVCC(Multiversion concurrency control):

MVCC是数据库系统实现并发控制和一般系统中实现事务性内存控制的一种技术,主要用于并发控制,使用MVCC将读不会阻塞写,写不会阻塞读,只有两个线程写同一行数据可能导致冲突,

因此可以提供最高的并发性。MVCC对于并发写同一区域的数据可能导致冲突要求事务回滚或者互相等待资源导致死锁。

对于数据库系统来说,若一个用户正在读数据的同时,另一个用户正在写同一个数据,则读用户可能读到写到一半的数据或者不一致的数据,因此数据库系统都会使用并发控制。最简单的方式就是

写时阻塞所有读,这就是封锁技术。MVCC的方式是每个用户看到的数据是其连接上数据库时的快照,所有写操作对数据的改变其他数据库用户都不能看到,除非改变已经完成(即事务已提交)。

在MVCC中数据的更新使用delete(标记)+insert实现,因此对于同一行数据可能在数据库多个地方存在不同版本,旧数据和新数据不在同一个地方(不是就地更新),但只有最后一个版本是最新的,

之前的版本对于之前的事务有效。MVCC的好处是对于读数据来说,哪怕数据在整个事务过程中被别的用户修改删除,其读到的数据就是刚开始使用数据库时的那份数据。另外就是其不需要及时删除

旧数据,这样避免了系统来回换页导致性能下降。对于文档型数据库来说,还可以优化为数据存储在连续区块,delete+insert可以不更新里面部分数据,这样对于后续组装数据提供最大便利。MVCC

提供了即时的一致性视图,读写隔离,不需要进行封锁,因此可以提高并发性。

MVCC的图示:

图1:事务T1改变数据V1,将其改为数据V2,在堆中,数据如下图

图2:事务T3改变了V2,将其改为V3,在堆中,数据如下图:目前事务T2还在活动中,所以V1和V2属于recently dead状态,而不是真的dead状态。

图3:从可视性而言,事务T0只能看到数据V1。因为它早于事务T1启动。

图4:事务T1提交后,事务T2启动,此时事务T3尚未启动,故T2可以看到T1提交后的数据V2。

图5:事务T3提交后,事务T4启动,故T4只能看到数据V3。

图6: 前面说过,当还有事务活动中访问数据V1和V2,V1和V2的状态是recently dead。

当T0和T2都结束,已经没有事务在访问数据V1和V2了,此时V1和V2为dead状态,所以V1和V2都成为VACUUM的处理对象了。

以上几图以postgresql的MVCC实现为例描述了不同事务间读写操作过程以及其访问的数据。对于同时更新来说,主要多了

更新冲突检测,若更新存在读写依赖冲突则,更新失败,事务必须回滚,若存在互相依赖,则会解锁某一个事务,以避免死锁。

MVCC/COW在LMDB中的实现

LMDB对MVCC加了一个限制,即只允许一个写线程存在,从根源上避免了写写冲突,当然代价就是写入的并发性能下降。因为只有

一个写线程,所以不会不需要wal日志、读写依赖队列、锁队列等一系列控制并发、事务回滚、数据恢复的基础工具。MVCC的基础

就是COW,对于不同的用户来说,若其在整个操作过程中不进行任何的数据改变,其就使用同一份数据即可,若需要进行改变,比如

增加、删除、修改等,就需要在私有数据版本上进行,修改完成提交之后才给其他事务可见。

LMDB中,数据操作的基本单元是页,因此cow也是以页为单位,对应函数是mdb_page_touch,mdb_page_copy,copy真正实现页面复制,

touch调用copy完成复制,然后修改pgno后插入到B+Tree当中,这样对于此次事务,后续的操作访问的数据页就是最新的数据页面,而非

事务启动时对应的数据页面,且此页面与其他页面的关联关系仅在本事务页面列表中可见,对其他事务不可见。

实际上通过以上两个函数也实现了MVCC的核心,对于读写的控制,通过mdb_txn_begin控制,在其中,事务启动时会检查读写锁的情况,

若事务需要更新数据,则会被阻止,若只是读数据,则不管是否有写事务存在,读锁都可以获得。

MVCC的一个副作用就是对于存在大量写的应用,其数据版本很多,因此旧数据会占用大量空间,postgresql解决此问题通过vacuum命令,

LMDB中通过freedb解决,即将不再使用的旧的数据页面空间插入到一颗b-Tree当中,这样旧空间在所有事务不再访问之后就可以被LMDB

使用,从而避免了需要定期执行清理操作。当然其副作用是数据只能保持最新不能恢复到任意时刻,未执行vacuum之前,保存所有版本的数据库

可以恢复到任意时刻。

本文参考了如下资料,在此一并表示感谢。

https://en.wikipedia.org/wiki/Multiversion_concurrency_control

http://www.kuqin.com/system-analysis/20120319/319108.html

http://blog.chinaunix.net/uid-20726500-id-4040024.html

http://www.cnblogs.com/gaojian/p/3295951.html

lightning mdb 源代码分析(4)—MVCC/COW的更多相关文章

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

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

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

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

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

    本博文系列前面已经探讨了LMDB的系统架构.MMAP映射.B-Tree操作等部分,本文将尝试描述LMDB中的事务控制的实现. 事务的基本特征: 事务是恢复和并发控制的基本单位.它是一个操作序列,这些操 ...

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

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

  5. HBase源代码分析之HRegion上MemStore的flsuh流程(二)

    继上篇<HBase源代码分析之HRegion上MemStore的flsuh流程(一)>之后.我们继续分析下HRegion上MemStore flush的核心方法internalFlushc ...

  6. android-plugmgr源代码分析

    android-plugmgr是一个Android插件加载框架,它最大的特点就是对插件不需要进行任何约束.关于这个类库的介绍见作者博客,市面上也有一些插件加载框架,但是感觉没有这个好.在这篇文章中,我 ...

  7. Twitter Storm源代码分析之ZooKeeper中的目录结构

    徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...

  8. 转:SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

  9. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

随机推荐

  1. Python OpenSource Project

    http://www.oschina.net/project/lang/25/python

  2. js: this,call,apply,bind 总结

    对js中的一些基本的很重要的概念做一些总结,对进一步学习js很重. 一.this JavaScript 中的 this 总是指向一个对象,而具体指向那个对象是在运行时基于函数的执行环境动态绑定的,而非 ...

  3. ios学习总结(1) -- 创建第一个ios项目

    原文地址 下载并打开xcode. 接着新建一个工程,如下图所示: 点击Create a new Xcode project,之后选择ios下的Application,点击Single View App ...

  4. PHP 5.4中的traits特性

    Trait 是 PHP5. 中的新特性,是 PHP 多重继承的一种解决方案.例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情,Trait 就是为了解决这个问题. 简单使用 ...

  5. A session had already been started - ignoring session_start() 解决方法

    A session had already been started - ignoring session_start() --已经存在一个session 打开了 -- 忽略sessioon_star ...

  6. node.js简单的页面输出

    在node.js基本上没有兼容问题(如果你不是从早期的node.js玩起来),而且原生对象又加了这么多扩展,再加上node.js自带的库,每个模块都提供了花样繁多的API,如果还嫌不够,github上 ...

  7. AppInventor学习笔记(四)——打地鼠应用学习

    一.组件设计 1.整体预览 2.图片精灵的添加 (1)首先加入一个画布进去 调节属性如图 (2)添加精灵 添加精灵,然后上传张图片进行属性修改 3.加入Clock 直接加入,设定为1000ms 二.B ...

  8. SqlServer2005或2008数据库字典--表结构.sql

    SELECT TOP 100 PERCENT --a.id,       CASE WHEN a.colorder = 1 THEN d.name ELSE '' END AS 表名,       C ...

  9. [MySQL]安装和启动

    一 MySQL简介 1)MySQL MySQL是MySQL AB公司的数据库管理系统软件,是最流行的开源(Open Source,开放源代码)的关系型数据库管理系统. 2) MySQL具有以下主要特点 ...

  10. MAXIMO系统 java webservice 中PDA移动应用系统开发

    MAXIMO系统 java webservice 中PDA移动应用系统开发  平时经常用的wince PDA手持设备调用c#写的webservice, 当然PDA也可以调用java webservic ...