锁的获取
当线程已经持有的锁比新申请的锁更强时,认为已经持有了锁,无需再对申请锁类型加锁。锁的强弱指持有的锁与其他锁的不兼容集合大小,集合相同锁相同,集合更大锁更强,否则无强弱关系。通过锁的兼容位图进行简单的位运算即可快速判断锁的强弱。
按照锁的适用范围将锁划分为两类,当然划分不是非此即彼的,会有重叠,这两类锁有各自的兼容性和锁对象管理方式。
●范围锁(scoped locks)
只有三种锁(IX,S,X),主要用于GLOBAL、COMMIT、TABLESPACE、BACKUP_LOCK命名空间的对象。这几种命名空间的锁主要从整体上去限制并发操作,比如在DML访问一张表时,会先申请一个该表所属SCHEMA的IX锁,避免访问过程中该SCHEMA被修改、删除。范围锁全局每种命名空间都仅有一个锁对象,从而实现全局性的并发控制。
●对象锁 (per-object locks)
除了IX锁,其他类型都可以用于其他命名空间,这部分是最常用的锁类型。主要用于对数据库的某个具体元数据的并发控制。这类锁对象会比较多,对其有独特的管理,本文不再展开说明。
根据锁的兼容性、以及通用性将锁分为两类。
unobtrusive锁相互间兼容,并且适用于所有DML操作。这类锁获取后不用记录下具体哪个线程申请的,只需要记录下有多少个请求已经获得,通过锁对象下64位原子变量来计数,因此对其他连接的锁申请影响很小,表现比较低调。在64位中每种类型锁都有由固定的位范围存放加锁个数。对于scoped与per-object是不同锁对象,因此位分别设置。
scoped locks: IX(0~59位)
per-object locks: S,SH(0~19位),SR(20~39位), SW(40~59位)
注意分配20位的不会产生溢出,因为当前设计不会同时有超过2^20 - 1个连接。
另外,还存在三个状态指示位,用于加速锁的处理。
IS_DESTROYED: 标识锁对象将被释放。
HAS_OBTRUSIVE:标识锁对象下有obtrusive锁,新的锁申请必须进入慢速申请路径,释放锁时,也要先加锁以保护已授予锁链表。
HAS_SLOW_PATH: 标识锁对象下是否有unobtrusive锁。
相互间不兼容,对于DML操作不通用。此类锁的申请过程需要对锁对象的读写锁加写锁,对不同线程的锁申请影响较大,因此显的比较张扬。
scoped locks:X,S。
per-object locks:SU, SRO, SNW, SNRW, X。
锁的申请过程分为两种路径,1)快路径, 即只需要增加锁个数计数来授予锁; 2)慢路径,需要对锁对象读写锁加写锁来授予锁。
对于unobtrusive锁,可以通过快速路径来快速授予锁。但是授予锁有个前提,就是该锁对象下没有obtrusive锁,因为unobtrusive与obtrusive之间有些锁是互斥的,只有在没有obtrusive锁存在时,unobtrusive锁才彼此兼容。通过检测锁状态的HAS_OBTRUSIVE位即可快速判断。通过CAS操作即可更新锁个数,同时也会检测是否已有其他线程以张扬方式申请了锁。CAS操作成功,即申请锁成功。
对于obtrusive锁,以及当前申请unobtrusive锁,而锁对象下已经持有obtrusive锁时,需要进入慢路径申请锁,即先对锁对象下的读写锁加写锁。在当前锁对象首次进入慢路径时,设置锁状态的HAS_SLOW_PATH位。如果是首次申请obtrusive锁,则设置HAS_OBTRUSIVE位。
锁对象的快速路径锁申请锁、已经授予的锁队列、正在等待锁队列都有标识其含有锁类型的锁位图,通过位图可以加快锁兼容判断速度,避免每次遍历锁队列。
在申请obtrusive锁进入慢路径之前,要将当前线程通过快路径获取的锁物化,即从锁对象的锁状态计数器中减除,并放入到锁对象的已经授予锁列表中。因为锁状态计数器中只有锁个数,不区分线程。而当前线程自己申请的unobtrusive锁与obtrusive锁不冲突。物化可以确保锁状态计数器中都是其他线程申请的,这样就可以通过快速路径锁位图快速判断是否与当前申请锁兼容。
当且仅当满足如下两个条件时,才可以授予锁。
1. 其他线程没有持有不兼容类型锁。
2. 当前申请的锁的优先级高于请求等待列表中的。
首先通过锁位图判断等待队列,不兼容则不能授予锁。再判断快速路径,不兼容则不能授予锁。最后判断授予锁队列,都兼容则授予锁,不兼容,需要遍历持有锁队列,检查是否其他线程持有不兼容锁,是则不能授予,否则可以授予锁。
关于亚信安慧AntDB数据库
AntDB数据库始于2008年,在运营商的核心系统上,服务国内24个省市自治区的数亿用户,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔通信核心交易,保障系统持续稳定运行超十年,并在通信、金融、交通、能源、物联网等行业成功商用落地。