虽然Mutex中文翻译为互斥锁,但为了和OS mutex充分的区别,所以我们在本文里称Oracle Mutex为Mutex。
Oracle中的mutex,类似于Latch,是一种低级的串行机制,用以控制对SGA中部分共享数据结构的访问控制。 Oracle中的串行机制有不少,引入它们的目的是避免一个对象出现下述现象:
- 当某些进程在访问该对象时,该资源被重新分配
- 当某些进程在修改它时,被其他进程读取
- 当某些进程在修改它时,被其他进程修改
- 当某些进程在读取它时,被其他进程修改
不同于Latch,Mutex的使用更灵活,用途更多,例如:
- 哪些需要被mutex保护的共享数据结构可以有自己独立的mutex,即一个对象拥有自己独立的mutex,不像Latch往往一个需要保护大量对象,举例来说,每一个父游标有其对应的mutex,而每一个子游标也有其对应的mutex
- 每一个数据结构可能有一个或多个mutex保护,每一个mutex负责保护其结构的不同部分
- 当然一个mutex也可以用来保护多于一个的数据结构
理论上mutex即可以存放在其保护的结构本身中(其实是嵌入在结构里),也可以存放在其他地方。一般情况下Mutex是在数据结构需要被保护时动态创建出来的。如是嵌在需要保护结构体内的mutex,则当所依附的数据结构被清理时该mutex也将被摧毁。
Mutex带来的好处
虽然mutex和latch都是Oracle中的串行机制,但是mutex具有一些latch没有的好处
更轻量级且更快
Mutex作为Latch的替代品,具有更快速获得,更小等优势。获取一个mutex进需要大约30~35个指令,而Latch则需要150~200个指令。一个mutex结构的大小大约为16 bytes,而在10.2版本中一个latch需要112个bytes,在更早的版本中是200个bytes。从200个bytes 精简到112个是通过减少不必要的统计指标 SLEEP1~SLEEP11、WAITERS_WOKEN, WAITS_HOLDING_LATCH等从而实现的。今后我们将看到更多关于Latch的代码优化。
减少伪争用
典型情况下一个Latch保护多个对象。当一个Latch保护多个热对象时,并行地对这些对象的频繁访问让latch本身变成性能的串行点。这也就是我们此处说的伪争用点,因为争用是发生在这个串行保护的机制上,而不是进程去访问的对象本身。与latch不同,使用mutex的情况下Oracle开发人员可以为每一个要保护的数据结构创建一个独立的mutex。这意味着Latch的那种伪争用将大大减少,因为每一个对象均被自己独立拥有的mutex保护
Mutex在一些地方替代了latch和PIN
一个Mutex可供多个Oracle进程并行地参考,反过来说进程们可以以S(Shared 共享) mode模式参考一个Mutex。以S mode一起共享参考这个mutex的进程的总数成为参考总数reference count。Mutex自身结构中存放了这个ref count的数据。另一方面,mutex也可以被以X (Exclusive)mode排他模式被仅有一个进程所持有Held。
Mutex有2种用途,一方面他们可以充当维护必要串行机制的结构,如同latch那样;同时也可以充当pin,避免对象被age out。
举例来说,mutex结构中包含的ref count信息可以用作替代library cache pin。在mutex充当cursor pin之前,当一个进程要执行=>pin一个cursor时需要做的是针对性地创建library cache pin和删除这个library cache pin(均为S mode)。mutex充当cursor pin之后,进程只需要增加和减少mutex上的ref count即可。
当某一个进程首次解析一个游标 Cursor,他将临时创建并移除一个library cache pin,但是该进程后续的解析或执行进要求增加或者减少ref count。注意在这个增加/减少ref count的过程中无需acquire latch,这是因为mutex自身能起到限制串行访问修改ref count的作用。当一个进程要移除自己的mutex pin时,它减少ref count,同样的无需acquire 任何latch。
Mutex和Latch的交互
Latches和Mutex 是独立的串行机制,举例来说一个进程可以同时持有latch和mutex。在进程异常dead的情况下,一般latch要比Mutex更早被PMON清理。一般情况下不存在mutex的死锁。不像latch,在早期版本例如9i之前我们经常遇到latch死锁的问题。
Mutex的用途
在版本10.2中仅仅有 KKS 这个内核层是mutex的客户,KKS 意为 Kernel Kompile Shared,它是Library Cache中的shared cursor游标共享部分层次的代码。在之后的版本中,ORACLE开发部门更多地使用了Mutex,不局限于KKS。
KKS游标共享如何使用Mutex
kks 使用mutex以便保护对于下述基于parent cursor父游标和子游标child cursor的一系列操作。
对于父游标parent cursor的操作:
- 基于发生的不同操作,对应不同的等待事件:
- 在某个父游标名下创建一个新的游标 ==> cursor:mutex X
- 检查一个父游标 ==> cursor:mutex S
- 绑定值捕获 ==> cursor:mutex X
- 保护父游标的mutex嵌入在父游标结构内
- 针对父游标parent cursor的Mutex类型为’Cursor Parent’ (kgx_kks2).
- 针对父游标parent cursor的Mutex等待事件均为’ Cursor: mutex *’的形式
针对游标统计信息的操作
- 基于对不同的游标统计信息的操作有不同的等待事件:
- 构造,更新游标相关的统计信息 ==> cursor:mutex X
- 检测游标相关的统计信息,例如访问V$SQLSTATS ==> cursor : mutex S
- 相关的游标可能在父游标中,也可能在游标统计信息相关的hash table上
- 针对游标统计信息的Mutex类型为Cursor Stat (kgx_kks1)
- 针对游标统计信息r的Mutex等待事件均为’ Cursor: mutex *’的形式
首先我们会在环境中模拟cursor pin S wait on X的场景,并通过systemstate dump和v$mutex_sleep , v$mutex_sleep_history等视图观察这一现象
to be continued ……………………………