ITPub博客

首页 > 数据库 > > Berkeley DB的锁占用困惑?

Berkeley DB的锁占用困惑?

作者:u_9ff4c058a0e0 时间:2022-04-14 16:45:05 0 删除 编辑
作者:熊蛙
链接:https://www.zhihu.com/question/22522986/answer/23672417


这个问题是典型的防止写线程(或进程)被读共享锁霸占导致饿死的问题。主流数据库都有对应的策略,一般情况下不会出现写操作饿死,不需要额外的干预。

Berkeley DB的锁是基于数据页(Page)为单位的,允许多个事务并发执行。在数据库外人为增加的队列、文件锁等行为,相当于加了一把全局锁,对数据库的并发性能有影响。一般情况下不建议这样做。

此外,对于并发读写数据库,还需要充分考虑和避免死锁情况。参考:

http://docs.oracle.com/cd/E17076_03/html/gsg_txn/C/blocking_deadlocks.html#deadlocks

以下是对Berkeley DB锁系统防止写请求饿死的简要原理描述,实际实现涉及到很多细致的优化实现,会比原理描述复杂。

==================

数据库系统的性能至关重要,为了减轻锁粒度、提高并发性能,其内部锁系统设计相当复杂精巧。以Berkeley DB为例,锁系统中包括锁(Lock)、锁持有者(Locker)和被锁对象(Object)。可简单地认为锁持有者对应于读写事务,被锁对象对应于数据页。

Berkeley DB设计文档(src/lock/Design)指明:内部锁系统,对于被锁对象(Object),维护着holders和waiters两个链表。

        OBJECT                   -----------------------
        HASH                     |                     |
                             ----|-------------        |
        ________    _______  |   |   ________ |        |
        |       |-->| O1  |--|---|-->|  O2  | |        |
        |_______|   |_____|  |   |   |______| V        |
        |       |    W  H--->L1->L2   W  H--->L5       |        holders
        |_______|    |       |   |    |                V
        |       |    ------->L3  \    ------->L6------>L7       waiters
        |_______|           /     \            \
        .       .          /       \            \
        .       .          |        \            \
        .       .          |         \            -----------
        |_______|          |          --------------        |
        |       |      ____|____                ___|_____  _|______
        |_______|      |       |                |       |  |      |
        |       |      | LID1  |                |  LID2 |  | LID3 |
        |_______|      |_______|                |_______|  |______|
                           ^                        ^        ^
                           |                        |        |
                        ___|________________________|________|___
               LOCKER   |    |    |    |    |    |    |    |    |
               HASH     |    |    |    |    |    |    |    |    |
                        |    |    |    |    |    |    |    |    |
                        |____|____|____|____|____|____|____|____|


         * Figure out if we can grant this lock or if it should wait.
         * By default, we can grant the new lock if it does not conflict with
         * anyone on the holders list OR anyone on the waiters list.
         * The reason that we don't grant if there's a conflict is that
         * this can lead to starvation (a writer waiting on a popularly
         * read item will never be granted)... 

src/lock/lock.c中的注释指出,为了防止饿死,所申请的锁必须与现有的holders和waiters都不冲突,才能授予(成为holder)。否则将会被加到waiters中。

举例说明:对于某数据页面,目前holders中有10个读锁。写请求到达时,由于写锁与读锁冲突,申请的写锁会被加到waiters列表中。后续如果有新的读请求到达,此时waiters列表中已经有与之冲突的写锁占据,所以该读锁无法即时成为holder,必须加到waiters中等待写锁被释放。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69999831/viewspace-3144967/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2022-02-11

  • 博文量
    1828
  • 访问量
    20617