dirty reader怎样 不被writor block住?

如数据库支持dirty read, 则 所有打开的dbhandle都配置 DB_READ_UNCOMMITTED;

在线程拿到 write锁并做完处理后(比如splite one page), 降为 was_write锁. WWRITE锁和dirty reader不会冲突;

对dirty read锁的请求会被优先处理;

dirty read锁在 读取完成后马上释放; why? 因为txn保留读锁是为了repeatable read.

若cursor 为read_uncommitted, 处理对读锁的请求时, lock_mode会改为 DB_LOCK_READ_UNCOMMITTED (db_meta.c, db_lget);

txn abort的时候 把 was_write锁 重新 升级为 write锁. 因为abort->undo时需要写page. (txn.c, txn_abort())

代码阅读:

db.h

typedef enum {
DB_LOCK_NG=, /* Not granted. */
DB_LOCK_READ=, /* Shared/read. */
DB_LOCK_WRITE=, /* Exclusive/write. */
DB_LOCK_WAIT=, /* Wait for event */ // 用于queue am
DB_LOCK_IWRITE=, /* Intent exclusive/write. */ // Intent锁用于hierarchy锁
DB_LOCK_IREAD=, /* Intent to share/read. */
DB_LOCK_IWR=, /* Intent to read and write. */
DB_LOCK_READ_UNCOMMITTED=, /* Degree 1 isolation. */
DB_LOCK_WWRITE= /* Was Written. */
} db_lockmode_t;

lock/lock_region.c:

#define    DB_LOCK_RIW_N    9
static const u_int8_t db_riw_conflicts[] = {
/* N R W WT IW IR RIW DR WW */
/* N */ , , , , , , , , ,
/* R */ , , , , , , , , ,
/* W */ , , , , , , , , ,
/* WT */ , , , , , , , , ,
/* IW */ , , , , , , , , ,
/* IR */ , , , , , , , , ,
/* RIW */ , , , , , , , , ,
/* DR */ , , , , , , , , , // dirty read 和was_write不冲突
/* WW */ , , , , , , , ,
};

lock.c,  __lock_get_internal(): dirty read锁优先处理

    lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
sh_off = R_OFFSET(&lt->reginfo, sh_locker);
  // 遍历holder列表
for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
if (sh_off == lp->holder) { // 已经hold 锁了
if (lp->mode == lock_mode && lp->status == DB_LSTAT_HELD) {
lp->refcount++;
lock->off = R_OFFSET(&lt->reginfo, lp);
lock->gen = lp->gen;
lock->mode = lp->mode;
goto done;
} else {
ihold = ;
}
} else if (__lock_same_family(lt,
R_ADDR(&lt->reginfo, lp->holder), sh_locker))
ihold = ;
else if (CONFLICTS(lt, region, lp->mode, lock_mode))
break;
else if (lp->mode == DB_LOCK_READ || lp->mode == DB_LOCK_WWRITE) {
grant_dirty = ; // holder列表只有读锁; 或者有一个ww锁
holder = lp->holder;
}
} if (lp != NULL) { // 有冲突的holder
if (ihold || LF_ISSET(DB_LOCK_UPGRADE) || lock_mode == DB_LOCK_READ_UNCOMMITTED)
action = HEAD; // dirty read请求 优先, 放入waiter队列头
else
action = TAIL;
} else {
if (LF_ISSET(DB_LOCK_UPGRADE))
action = UPGRADE;
else if (ihold)
action = GRANT;
else {
       // 无冲突的holder; 遍历waiter列表
SH_TAILQ_FOREACH(lp, &sh_obj->waiters, links, __db_lock)
if (lp->holder != sh_off && CONFLICTS(lt, region, lp->mode, lock_mode))
break; if (lp == NULL) // 无冲突的waiter
action = GRANT;
else if (grant_dirty && lock_mode == DB_LOCK_READ_UNCOMMITTED) {
lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);
if (lp->mode == DB_LOCK_WRITE && lp->holder == holder)
action = SECOND; // waiter表头 为一个upgrade请求. 当前DR放入第二个
else
action = GRANT; // 批准 DR锁请求.
} else if (lock_mode == DB_LOCK_READ_UNCOMMITTED)
          // 这里是DR请求, 但是!grant_dirty (没有read/ww holder). 这里有无冲突的holder;
          // 有冲突的waiter. ??????
action = SECOND;
else
action = TAIL;
}
}
db_meta.c, - write锁 downgrade wwrite锁:
__db_lget()
dbc->lock.pgno = pgno;
... switch (action) {
default:
if (has_timeout)
goto do_couple;
ret = __lock_get(env, dbc->locker, lkflags, &dbc->lock_dbt, mode, lockp); // 一般的处理
break; case LCK_DOWNGRADE:
couple[0].op = DB_LOCK_GET;
couple[0].obj = NULL;
couple[0].lock = *lockp;
couple[0].mode = DB_LOCK_WWRITE; // 请求一个新的 wwrite锁
UMRW_SET(couple[0].timeout);
i++;
/* FALLTHROUGH */
case LCK_COUPLE:
do_couple: couple[i].op = has_timeout? DB_LOCK_GET_TIMEOUT : DB_LOCK_GET;
couple[i].obj = &dbc->lock_dbt;
couple[i].mode = mode; // 对传入的 pgno 请求 一个 新的 锁,
UMRW_SET(couple[i].timeout);
i++;
if (has_timeout)
couple[0].timeout = F_ISSET(dbc, DBC_RECOVER) ? 0 : txn->lock_timeout;
if (action == LCK_COUPLE || action == LCK_DOWNGRADE) {
couple[i].op = DB_LOCK_PUT; // 释放原来的锁 (downgrade的话, 就是原来的 write锁, 从而实现了 锁降级)
couple[i].lock = *lockp;
i++;
} ret = __lock_vec(env, dbc->locker, lkflags, couple, i, &reqp);
if (ret == 0 || reqp == &couple[i - 1])
*lockp = i == 1 ? couple[0].lock : couple[i - 2].lock; // i != 1标识 LCK_DOWNGRADE, 返回新的 wwrite锁
break;
} __db_lput()
if (F_ISSET(dbc->dbp, DB_AM_READ_UNCOMMITTED) && !F_ISSET(dbc, DBC_ERROR) && lockp->mode == DB_LOCK_WRITE)
action = LCK_DOWNGRADE;
else if (dbc->txn == NULL)
action = LCK_COUPLE; // 这里的couple是直接释放的意思. 非transaction情况
else if (F_ISSET(dbc, DBC_READ_COMMITTED | DBC_WAS_READ_COMMITTED) && lockp->mode == DB_LOCK_READ)
action = LCK_COUPLE; // read_commited, 且读锁
else if (lockp->mode == DB_LOCK_READ_UNCOMMITTED)
action = LCK_COUPLE; // read_uncommitted, 读锁, 直接释放
else
action = 0; env = dbc->env;
switch (action) {
case LCK_COUPLE:
ret = __lock_put(env, lockp);
break;
case LCK_DOWNGRADE:
couple[0].op = DB_LOCK_GET;
couple[0].obj = NULL;
couple[0].mode = DB_LOCK_WWRITE; // 获取 一个ww锁
couple[0].lock = *lockp;
UMRW_SET(couple[0].timeout);
couple[1].op = DB_LOCK_PUT;
couple[1].lock = *lockp; // 释放本来的锁 (写锁)
ret = __lock_vec(env, dbc->locker, 0, couple, 2, &reqp);
if (ret == 0 || reqp == &couple[1])
*lockp = couple[0].lock;
break;
default:
ret = 0; // 嗯, 这里. 如果default isolation level, 保留读锁; 写锁不降级的话, 也到这里.
break;
} return (ret);
}

berkeley db中 dirty read的实现的更多相关文章

  1. Berkeley DB基础教程

    一.Berkeley DB的介绍 (1)Berkeley DB是一个嵌入式数据库,它适合于管理海量的.简单的数据.如Google使用其来保存账户信息,Heritrix用其来保存froniter. (2 ...

  2. 免费数据库(SQLite、Berkeley DB、PostgreSQL、MySQL、Firebird、mSQL、MSDE、DB2 Express-C、Oracle XE)

    SQLite数据库是中小站点CMS的最佳选择 SQLite 是一个类似Access的轻量级数据库系统,但是更小.更快.容量更大,并发更高.为什么说 SQLite 最适合做 CMS (内容管理系统)呢? ...

  3. 了解 Oracle Berkeley DB 可以为您的应用程序带来 NoSQL 优势的原因及方式。

    将 Oracle Berkeley DB 用作 NoSQL 数据存储 作者:Shashank Tiwari 2011 年 2 月发布 “NoSQL”是在开发人员.架构师甚至技术经理中新流行的一个词汇. ...

  4. 一个简单的NoSQL内存数据库—Berkeley DB基本操作的例子

    一个简单的NoSQL内存数据库—Berkeley DB基本操作的例子 最近,由于云计算的发展,数据库技术也从结构式数据库发展到NoSQL数据库,存储模式从结构化的关系存储到现在如火如荼的key/val ...

  5. Berkeley DB基础教程 分类: H3_NUTCH 2014-05-29 15:21 2212人阅读 评论(0) 收藏

    一.Berkeley DB的介绍 (1)Berkeley DB是一个嵌入式数据库,它适合于管理海量的.简单的数据.如Google使用其来保存账户信息,Heritrix用其来保存froniter. (2 ...

  6. 新浪研发中心: Berkeley DB 使用经验总结

    http://blog.sina.com.cn/s/blog_502c8cc40100yqkj.html NoSQL是现在互联网Web2.0时代备受关注的技术之一,被用来存储大量的非关系型的数据.Be ...

  7. Berkeley DB 使用经验总结

    作者:陈磊 NoSQL是现在互联网Web2.0时代备受关注的技术之一,被用来存储大量的非关系型的数据.Berkeley DB作为一款优秀的Key/Value存储引擎自然也在讨论之列.最近使用BDB来发 ...

  8. Berkeley DB的数据存储结构——哈希表(Hash Table)、B树(BTree)、队列(Queue)、记录号(Recno)

    Berkeley DB的数据存储结构 BDB支持四种数据存储结构及相应算法,官方称为访问方法(Access Method),分别是哈希表(Hash Table).B树(BTree).队列(Queue) ...

  9. 比Redis更快:Berkeley DB面面观

    比Redis更快:Berkeley DB面面观 Redis很火,最近大家用的多.从两年前开始,Memcached转向Redis逐渐成为潮流:而Berkeley DB可能很多朋友还很陌生,首先,我们简单 ...

随机推荐

  1. ubuntu 双线双网卡双IP实现方式

    昨天金桥机房上架了一台多玩的测试机,系统是ubuntu9.04 X64的系统,母机IBM X336机器.用户需求是双线,故采用一个网卡配置电信地址,另一个网卡配置联通地址,安装好系统后配置好IP发现联 ...

  2. [转载] Android Bander设计与实现 - 设计篇

    本文转载自: http://blog.csdn.net/chenxiancool/article/details/17454593 摘要 Binder是Android系统进程间通信(IPC)方式之一. ...

  3. [2015hdu多校联赛补题]hdu5301 Buildings

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5301 题目大意:给你一块由1x1方格组成的矩形区域,其中有且仅有一个坏块,现在你要在上面建矩形的房子, ...

  4. python第十八天-----Django基础

    1.路由系统 a.普通路由 url(r'^index$', views.index), b.正则路由 url(r'^index/(\d*)', views.index), url(r'^manage/ ...

  5. asp.net web.config 设置Session过期时间

    在Asp.net中,可以有四处设置Session的过期时间:(原文作者:望月狼地址:http://www.cnblogs.com/wangyuelang0526/) 一.全局网站(即服务器)级 IIS ...

  6. webpack配置sass模块的加载

    webpack管理的项目,我们希望用sass定义样式,为了正常编译,需要做如下配置.这里不讲webpack的入门,入门的文章,我推荐这篇<webpack入门>. 为了使用sass,我们需要 ...

  7. git 配置忽略文件(忽略UserInterfaceState.xcuserstate,Breakpoints_v2.xcbkptlist)

    ios 配置忽略文件.gitignore 文件 之前新建了一个项目,在使用git管理版本的时候没有配置忽略文件 .gitignore 文件,结果导致每次提交的时候都会出现UserInterfaceSt ...

  8. C++ Primer Plus 笔记记录

    (一) /a 这个转移字符竟然能调用计算机的硬件 喇叭~~ 对于float c++只能保证6位有效数字 似乎 double是13位 cout.setf(ios_base::fixed, ios_bas ...

  9. js自定义对象

    一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascrip ...

  10. 利用matlab摄像机标定

    (1)输入图像 "Image names"键 Matlab的图形窗口显示出20幅靶标图像 (2) 提取角点 "Extract grid corners"键. 输 ...