Oracle lock&latch

1. 概述

4种锁机制

  • lock
  • latch
  • pin
  • mutex

保证资源在并发访问和修改时不被破坏

锁类型 行为 持有时间 级别 保护类型
lock 队列(先到先服务) Enqueues: 多个, 复杂(KGL锁: 共享/独占) 对象
pin 队列(先到先服务) 共享/独占
latch 随机抢占 共享/独占 共享内存
mutex 随机抢占 长(某些mutex) 共享/独占

2. 几种内存结构

  • 数组

    相同形状和大小的对象列表.

    x$ksuse: 用户会话的结构体, v$session视图的基表.

  • 指针

    内存地址.

  • 链表

    相对少量的相关项.

    undo段头事务表(事务控制)

    index叶子块

    • 双向链表

    • 单向链表

数组适合处理定长结构, 链表非常适合处理相对少量的相关项, 这2种情况下需要遍历整个数组或者链表来查找某项, 如果项数少的话是可以的. 如何处理大量持续出现和消失的项, 并且每次都需要快速定位其中一项?

  • 散列表

    hash cluster: 散列聚簇.

    图1: hash cluster管理

    每个latch管理多个hash bucket, 每个hash bucket管理一条hash chain(双向链表), 指向具体的block地址.

    图2: 双向链表操作

    hash chain对象会有LRU算法维护大小. 并且会维护hash chain的原子操作.

3. Latch

根据latch的类型分为:

  • 独占
  • 共享

根据latch的活动分为:

  • willing to wait

  • immediate get

本质上, latch是一块内存位置和一个用于检查更新内存位置的CPU原子操作.

  • 独占latch

    获取伪操作:

    • 设置寄存器X, 指向latch内存地址A
    • 如果内存地址A的值是0, 那么将它设置为0xff <= CPU原子操作
    • 如果内存地址A的值设为0xff, 那么就"持有"latch
    • 如果不是, 就回到最上一步重试, 持续尝试N次

    CPU原子操作, "Test and Set"CPU指令

    持续尝试是spin的过程:

    图3: spin过程

  • 共享latch

    实现要复杂很多, 应用在一些最繁忙的代码区.

    CPU架构中更精细的比较(compare)和交换(swap)操作, 简称CAS

    CAS涉及3个操作数:

    • 内存值V
    • 旧的预期值A
    • 要修改的新值B

    "我认为V的值应该是A, 如果是, 那么将V的值更新为B; 如果不是, 不修改并告诉我V的实际值是多少." 当且仅当预期值A和内存值V相同时, 将内存值V修改为B, 否则什么都不做.

      int compare_and_swap (int* reg, int oldval, int newval)
    {
    ATOMIC();
    int old_reg_val = *reg;
    if (old_reg_val == oldval)
    *reg = newval;
    END_ATOMIC();
    return old_reg_val;
    }

    典型的操作伪码:

    • 设置标志F为0
    • 设置寄存器X指向latch的地址L
    • 设置寄存器Y的值为L目前的值
    • 设置寄存器Z的值为你想要在L上设置的新值
    • 如果Y的值等于L的值, 那么设置"L的值"为"Z的值", 并设置标志F为1 <= CPU原子操作
    • 如果标志F的值为1, 那么你已经成功地修改了latch的值

    图4: CAS逻辑图

    设置Flag的优点在于可以允许多个读者"获取和释放latch时进行增减计数", 同时也允许"写者"设置"独占写"位来阻塞新的读者(和其他写者).

    读者请求:

    • 循环(自旋)N次
    • 如果设置了写标志位, 那么回到循环的开头
    • 尝试将latch值加1(以获得读权限)
    • 如果标志位已设置, 退出循环

    当读进程完成了读操作, 使用类似循环把latch的标志位减小1

    写者请求(独占):

    • 循环(自旋)N次
    • 如果写标志位已经设置, 那么回到循环的开头
    • 尝试将latch值设为"写标志位+当前值" (获取写标志)
    • 如果标志已经设置, 那么推出循环
    • 等待读标记减小为0

    允许写进程在读进程正在使用资源时抢占"独占"位, 然后等待读进程对标志位减少至0. 同时新的读进程在写进程持有写位时不能够增加标志位, 并且同一时刻只有一个写进程持有写标志位, 这样对读进程来说, 最大化了读共享, 同时最小化了写进程延迟.

    latch值 解释
    0x00000005 当前有5个进程以共享方式持有latch
    0x40000003 当前有3个进程以共享方式持有latch, 但有一个独占写进程(无法得知是谁)已经设置了阻塞位来禁止新的读进程
    0x20000014 进程0x14(v$process.pid)正以独占方式持有latch
  • latch统计

    v$latch, v$latch_parent, v$latch_children

    统计项 解释
    gets willing to wait方式获取latch的次数. 最终成功得到latch的次数累积.
    misses willing to wait方式获取latch, 并在首次test and set/compare and swap失败时的次数.
    spin_gets willing to wait方式获取latch, 首次test and set/compare and swap失败后spin的次数.
    sleeps willing to wait方式获取latch, 在自旋(spin)后仍然失败的次数.
    sleep1... sleep11 willing to wait方式获取latch, 休眠的次数.
    immediate_gets 立即模式获取latch的次数, 最终成功得到latch的次数累计.
    immedaite_misses 理解模式获取latch, 并在首次test and set/compare and swap失败时的次数.
    wait_time session等待该latch的总等待时间, 仅是willing to wait的latch, 单位是微妙.

    首次尝试未得到latch时的活动汇总:

    需要的latch访问 使用方式
    获取独占latch 尝试立即获取, 进入spin自旋循环一次. 附加到等待列表, 尝试理解获取, 进入休眠.
    以独占模式获取其他进程正以某种模式(共享/独占/处于阻塞)持有的可共享latch 进入spin循环, 附加至等待列表, 重复spin循环, 如果不成功则进入休眠.
    以共享模式获取其他进程以独占/阻塞模式持有的可共享latch 不进入spin状态, 直接附加到等待列表.
    以共享模式获取其他进程以共享模式持有的可共享latch 休眠前仅spin循环cpu_count +2次

    关键: 当前进程无法得到latch时, 会附加到一个列表中, 然后等待被唤醒.

    post/wait机制: 当前持有latch的进程, 在它释放latch时, 会通知(post)位于列表顶端的进程.

    _enable_reliable_latch_waits参数控制

    图5: post/wait机制


    Mutex

    Mutex的实现和使用和latch很类似. 在library cache处理中用以替代pin.

    Mutex本质上是一个"私有的小型latch", 作为library cache对象的一部分. Mutex替代了少量latch保护大量对象的方式 - 会引起latch竞争.

    每个library cache的hash bucket都有单独的Mutex.

4. Lock

回忆一下library cache的局部hash cluster结构.

图6: 局部library hash cluster

在这里, latch作为一项查找(或修改)内存对象的保护机制. 应该避免持有任意时间长度的latch. 当找到所需的内存对象时, 并做一些时间消耗的工作时, 需要一种不同的机制来保护这些内存对象, 以便能及时释放latch. 这就是下面要总结的库缓存锁(和pin).

  • 一些基础

    x$ksqrs: 排队资源

    x$ksqeq: 排队

    x$ktqdm: 表/DML锁

    x$ktcxb: 事务

    v$lock视图

    col_name type col describle
    ADDR RAW (4, 8) Address of lock state object
    KADDR RAW (4, 8) Address of lock
    SID NUMBER 会话的sid
    TYPE VARCHAR2(2) 该lock保护的对象类型:TM(DML enqueue), TX(Transaction enqueue), UL(User supplied)
    ID1/ID2 NUMBER 对于TM锁:ID1表示被锁定表的object_id, ID2为0. 对于TX锁:ID1是十进制值表示的改事务所占用的回滚段号和事务槽slot number号, ID2是十进制值表示的环绕wrap的次数, 即事务槽被重用的次数.
    LMODE NUMBER 0-none, 1-null(NULL), 2-row-S(SS), 3-row-X(SX), 4-share(S), 5-S/Row-X(SSX), 6-exclusive(X)
    REQUEST NUMBER 同LMODE, 大于0时, 表示当前会话被阻塞, 其他会话占有该锁的模式.
    CTIME NUMBER 已持有或者等待锁的时间
    BLOCK NUMBER 是否阻塞其他会话申请, 1:阻塞, 0:不阻塞

    锁模式

    模式 描述 解释 SQL操作
    0 none
    1 Null select
    2 SS(Row-S) 行级共享锁, 其他对象只能查询这些数据行 select for update, lock for update, lock row share
    3 SX(Row-X) 行级排他锁, 在提交前不允许做DML操作 insert/update/delete, lock row share
    4 S(Share) 共享锁 create index, lock share
    5 SSX(S/Row-X) 共享级排他锁 lock share row exclusive
    6 X(Exclusive) 排他锁 alter table, drop table, drop index, truncate table, lock exclusive

    Null: This lock mode doesn.t implement any restrictions for other session to acquire a lock but has the very important function of invalidating the session.s (holding the null lock) private cached information upon invalidation of the resource structure.

    Sub-Shared: To provide shared access to a part of the shared resource rather than the whole object, sub-shared lock mode is used so that exclusive access to other parts of an object can be provided.

    Sub-Exclusive: This mode is inline with Sub-Shared. This mode is held to provide exclusive access to a part of a shared resource, while other parts of the resource are being concurrently accessed.

    Shared: Sessions hold shared mode of a lock on a resource when it simply wants to inspect the resource and does not want to allow another session to modify this resource while providing concurrent access to that shared resource.

    Shared-Sub-Exclusive: This mode is a combination of Sub-Shared and Sub-Exclusive modes. This mode provides shared access to a part of a resource as well shared access to the whole resource.

    Exclusive: As it is exclusive, it prevents any concurrent access. This means when a session holds an exclusive lock on an object, no other session can have concurrent access to that shared resource.

    锁兼容性

    Gets/Held(->) N SS SX S SSX X
    N Yes Yes Yes Yes Yes Yes
    SS Yes Yes Yes Yes Yes No
    SX Yes Yes Yes No No No
    S Yes Yes No No No No
    SSX Yes Yes No No No No
    X Yes No No No No No
  • 锁实现

    Oracle Kernel Enqueue Service layer (KSQ)负责管理所有队列.

    当一个session需要访问一个资源时, 该session需要持有该资源结构的锁. 在持有资源结构锁之前, 需要连接到资源结构的相应队列上.

    每个资源结构都有3种队列(enqueue):

    • Owner Linked List
    • Waiter Linked List
    • Convertor Linked List

    转换队列优先级比等待队列高

    图7: 资源锁队列

    锁请求过程同样是Hash cluster模型:

    图8: 锁资源分配


    分析这样一个场景:

    有4个session处理一个有父/子(外键)关联的子表, 并且子表的外键约束上没有索引

    • session 37: del父记录1的唯一子记录

    • session 36: del父记录2的唯一子记录

    • session 39: 试图以独占模式锁住子表(begin waiting...)

    • session 37: 试图del父记录1(由于无FK索引, begin waiting...)

    • session 35: 试图del父记录3的唯一子记录(begin waiting...)

        select
      sid, type, id1, id2, lmode, request, ctime, block
      from
      type = 'TM'
      and
      id1 = 82772
      ;
    SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
    37 TM 82772 0 3 5 66 1
    36 TM 82772 0 3 0 42 1
    39 TM 82772 0 0 6 27 0
    35 TM 82772 0 0 3 3 0

    LMODE:3 - SX

    LMODE:5 - SSX

    LMODE:6 - X

    如下图等待图形

    图9: TM资源锁等待

    分析:

    • SID 35处于等待队列的末尾, 因为SID 39卡在前面.
    • SID 39必须等待转换队列中的SID 37.
    • 而SID 37卡在了转换队列, 因为它想从锁模式3转换到锁模式5, 同时SID 36在拥有者队列中正以锁模式3持有(3和5模式不兼容)

    随着进程提交(回滚), 队列将以如下步骤向前移动:

    • 当SID 36 commit, 拥有者队列会变空, 此时SID 37会从转换者队列转移到拥有者队列, 获取锁模式5并把ctime列重置为0. SID 39和35仍然会卡在等待者队列.
    • 当SID 37 commit, 拥有者队列再次变空, 然后SID 39将会转移到拥有者队列, 获取锁模式6并把ctime列设置为0. SID 35处于等待者头部, 但无法加入到拥有者队列, 因为锁模式6已被持有, 与锁模式3不兼容.
    • 当SID 39 commit, 拥有者队列再一次变空, 然后SID 35会移动到拥有者队列, 得到锁模式3并把ctime设置为0.

参考: http://www.oraxperts.com/node/103

[Oracle] Lock&Latch梳理的更多相关文章

  1. [Oracle] Redo&Undo梳理

    Oracle Redo&undo Oracle中的redo和undo是关键技术的核心, 诸如实例恢复, 介质恢复, DataGuard, 闪回机制等都是给予redo和undo的, 所以很有必要 ...

  2. Oracle内部latch获取函数简介

      标签: oracle call 函数   oracle statpack   转自: http://blog.51cto.com/458302/998775 Oracle的内部函数一直非常神秘,其 ...

  3. Oracle Lock 概述

    按锁的机制分类 排他锁( X ):如果事务T对对象A加上排他锁,则只允许T对A对象读取和修改,其他事务不能对A增加任何锁,直到T释放加载A上的排他锁 共享锁( S ):如果事务T对表A加上共享锁,则事 ...

  4. [整理]Oracle LOCK 机制

    数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.锁机制用于管理对 ...

  5. Oracle Lock(Enqueues)

    转载:http://www.cnblogs.com/Richardzhu/articles/2796540.html 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多 ...

  6. [MySQL] lock知识梳理

    MySQL Lock机制 INDEX: MySQL事务隔离级别 MVCC MySQL Lock类型 MySQL MDL CONTENT: 1. MySQL事务隔离级别 Read Uncommit RU ...

  7. ORACLE基础之oracle锁(oracle lock mode)详解

    ORACLE里锁有以下几种模式: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁,sub share  3:Row-X 行独占(RX):用于行的修改,sub exclusiv ...

  8. oracle lock

    数据库锁介绍:  https://www.cnblogs.com/springsnow/p/9990295.html#_label2_0 总结1:查询oracle锁定的表: 1.锁相关表 SELECT ...

  9. Oracle物化视图梳理

    --物化视图可以分为三种类型:* 包含聚集的物化视图* 只包含连接的物化视图* 嵌套物化视图三种物化视图的快速刷新的限制条件有很大区别,而对于其他方面则区别不大. --物化视图创建方式(Build M ...

随机推荐

  1. 微信小程序第3课 目录结构及小知识点

    目录 目录结构 安装包下载地址 一.pages目录介绍 二.index目录介绍 index.js(相当JavaScript文件,必不可少的) index.json(可以不需要) index.wxml( ...

  2. linux 查看CPU内存 网络 流量 磁盘 IO

    使用vmstat命令来察看系统资源情况 在命令行方式下,如何查看CPU.内存的使用情况,网络流量和磁盘I/O? Q: 在命令行方式下,如何查看CPU.内存的使用情况,网络流量和磁盘I/O? A: 在命 ...

  3. 大数运算:HDU-1042-N!(附N!位数的计算)

    解题心得: 这里使用了10000进制.很明显,因为是n!所以单个最大的数是10000*10000,使用万进制. 可以借鉴高精度的加法,单个乘了之后在进位. 很坑的一点,0!=1,数学不好WA了三次,尴 ...

  4. n个人排队都不站在原来的位置

    一.题目描述 有n个人首先站成一排,请问,当n个人第二次再重新排列,每个人都不在原来的位置上,问有多少种站法.例如,原来有3个人,ABC,那么第二次每个人都不在原来的位置上有2种站法,BCA和CAB, ...

  5. TI C6000优化手册——让代码看起来像钉子

    DSP芯片的出现,是为了解决大量的数字运算问题.通过集成专用的加法器.乘法器.地址产生器.复杂逻辑等硬件单元,DSP能实现比普通单片机更快速的数字运算,使处理器更适用于实时性高.复杂度强的处理场合.也 ...

  6. IOS开发学习笔记015-block和protocol

    一.block block 代码段    标识是 ^    block 和函数很像 1.可以保存代码 2.有返回值 3.有形参 格式 返回值 (block名)(形参列表) = ^(形参列表) {代码段 ...

  7. 【LoadRunner】利用lr_db_connect函数对Oracle数据库压测的完整流程

    项目中常常会有直接对数据库进行压测的需求,以前都是通过Jmeter实现的,但是Jmeter本身图表及结果收集方面没有Loadrunner那么强大,所以利用loadrunner工具自己的函数整理了一个脚 ...

  8. js 遍历对象属性(for in、Object.keys、Object.getOwnProperty) 以及高效地输出 js 数组

    js中几种遍历对象的方法,包括for in.Object.keys.Object.getOwnProperty,它们在使用场景方面各有不同. for in 主要用于遍历对象的可枚举属性,包括自有属性. ...

  9. 设计模式之迭代器模式 Iterator

    代码实现 public interface MyIterator { void first(); //将游标指向第一个元素 void next(); //将游标指向下一个元素 boolean hasN ...

  10. 零基础学习 Python 之字符串

    初识字符串 维基百科对于字符串的定义式:字符串是由零个或者多个字符组成的有限串行.你之前学会敲的第一行 print 代码里的 "Hello World",就是一个字符串.字符串的本 ...