由于我手里并没有Oracle的源代码(而兄弟伙又未必敢冒着进去的风险把手里的源代码给我看),所以只能借用postgresql来分析一下Oracle的latch机制了(为什么是latch而不是mutex?)。
在这里可以下载到postgresql的7.4.30源代码:http://www.postgresql.org/ftp/source/v7.4.30/
为什么会借用postgresql来分析Oracle的latch机制呢?
Oracle与postgresql都采用了共享内存以及多进程模型,两者在共享内存内的数据结构同步与互斥上,面临的问题是极其接近的。
postgresql的spinlock与latch机制相仿,解决的问题类似,只是名字和代码实现有些差异。
postgresql的spinlock实现在postgresql-7.4.30\src\backend\storage\lmgr\s_lock.c
/*
* s_lock(lock) - platform-independent portion of waiting for a spinlock.
*/
void
s_lock(volatile slock_t *lock, const char *file, int line)
{
/*
* We loop tightly for awhile, then delay using select() and try
* again. Preferably, "awhile" should be a small multiple of the
* maximum time we expect a spinlock to be held. 100 iterations seems
* about right. In most multi-CPU scenarios, the spinlock is probably
* held by a process on another CPU and will be released before we
* finish 100 iterations. However, on a uniprocessor, the tight loop
* is just a waste of cycles, so don't iterate thousands of times.
*
* Once we do decide to block, we use randomly increasing select()
* delays. The first delay is 10 msec, then the delay randomly
* increases to about one second, after which we reset to 10 msec and
* start again. The idea here is that in the presence of heavy
* contention we need to increase the delay, else the spinlock holder
* may never get to run and release the lock. (Consider situation
* where spinlock holder has been nice'd down in priority by the
* scheduler --- it will not get scheduled until all would-be
* acquirers are sleeping, so if we always use a 10-msec sleep, there
* is a real possibility of starvation.) But we can't just clamp the
* delay to an upper bound, else it would take a long time to make a
* reasonable number of tries.
*
* We time out and declare error after NUM_DELAYS delays (thus, exactly
* that many tries). With the given settings, this will usually take
* 3 or so minutes. It seems better to fix the total number of tries
* (and thus the probability of unintended failure) than to fix the
* total time spent.
*
* The select() delays are measured in centiseconds (0.01 sec) because 10
* msec is a common resolution limit at the OS level.
*/
#define SPINS_PER_DELAY 100
#define NUM_DELAYS 1000
#define MIN_DELAY_CSEC 1
#define MAX_DELAY_CSEC 100
int spins = 0;
int delays = 0;
int cur_delay = MIN_DELAY_CSEC;
struct timeval delay;
while (TAS(lock))
{
if (++spins > SPINS_PER_DELAY)
{
if (++delays > NUM_DELAYS)
s_lock_stuck(lock, file, line);
delay.tv_sec = cur_delay / 100;
delay.tv_usec = (cur_delay % 100) * 10000;
(void) select(0, NULL, NULL, NULL, &delay);
#if defined(S_LOCK_TEST)
fprintf(stdout, "*");
fflush(stdout);
#endif
/* increase delay by a random fraction between 1X and 2X */
cur_delay += (int) (cur_delay *
(((double) random()) / ((double) MAX_RANDOM_VALUE)) + 0.5);
/* wrap back to minimum delay when max is exceeded */
if (cur_delay > MAX_DELAY_CSEC)
cur_delay = MIN_DELAY_CSEC;
spins = 0;
}
}
}
代码里的select函数就是IO多路复用里的select,你没有看错,就是IO多路复用里的select(最新的已经改成pg_usleep()了),在这里,select仅仅做了休眠的工作,跟IO多路复用没有任何关系。select在这里仅仅起到把当前进程丢入操作系统内核的wait queue链表里去直到delay这个结构体描述的时间之后,再把这个进程从wait queue取出来挂接到running queue里去。
但是,遍历两个链表(时间复杂度是圈N),以及队列指针修改之后,CPU跟着做的context switch是非常耗费CPU资源的工作,而这样的工作,发生的频率是毫秒(millisecond)级别的。所以,这种函数(select这种会引起context switch)尽量少用。这也是,spinlock相对于传统的排队型锁的优势。
这种spinlock的test and set、spin这种操作的本身是比较容易的。直接写个while循环,不断执行"=="这样的C语言语句就行了。不过,spinlock里有个机制是sleep操作,就是当某进程spin了很长时间之后,发现还是无法获取到资源,这个时候就会让这个进程sleep。
关键点就在这里了。恩。Oracle或者postgresql只是一个应用软件,它不具备让一个进程休眠的能力,应用软件(用C或者比C更软的语言)最多只能操作内存和写逻辑,它要么在跑,要么跑完了退出,绝对不会有别的状态(其实,所谓的进程的状态是操作系统内核意淫出来的,就是task_struct结构体里的state字段的值是多少。从CPU的角度来讲,它并不care),如果想要有别的状态,就必须调用系统api,通过0x80号陷阱进入操作系统内核的代码,修改该进程(或者别的进程,只要具备足够的权限)的task_struct的state的数值(0,1,2,3,4...)。
所以,无论是Oracle或者是postgresql或者是别的什么数据库或者别的什么server软件,只要它想实现一种锁机制,而这种锁机制具备sleep的功能,它就必须要借用操作系统的api,也就是说,这种锁是操作系统api之上的衍生品,这么说起来,即便Oracle也是操作系统之上的衍生品。
当然,从理论上来讲,也可以自己写一个数据库,这个数据库不建立在操作系统之上,它具备任务、文件系统的管理功能,它是无敌的。是的。理论上来讲是这样的。不过,如果有人这样做了,那么他的脑袋一定被门夹了。
分享到:
相关推荐
Oracle性能诊断之——Latch free
Latch free等待事件 Latch和lock的异同
- latch是一种Oracle低级别的内存保护机制,用于序列化对于非常短时间的内存结构的并发访问。 - latch是一种简单的内存结构。 - latch的大小通常在100-200B左右(取决于Oracle的版本和Oracle运行的平台)。 - latch...
Oracle中的Latch和Lock.pdf
Oracle Latch Contention
oracle latch描述以及使用
《oracle dba手记3:数据库性能优化与内部原理解析》由多位数据库技术专家合著而成,融合了各行业dba 的工作经验与思考,包含了精心挑选的数据库性能优化与内部原理解析案例。内容涵盖“dba 手记”,以手记形式记录...
深入解析Oracle -栓锁竞争与Latch优化实践
9.5.7 Oracle 10g/11g Latch机制的变化 467 第10章 性能诊断与SQL优化 471 10.1 使用AUTOTRACE功能辅助SQL优化 471 10.1.1 AUTOTRACE功能的启用 471 10.1.2 Oracle 10g AUTOTRACE功能的增强 473 10.1.3 ...
资源名称:Oracle DBA高可用、备份恢复与性能优化资源目录:第 1章 RAC真应用集群 11.1 单实例数据库并发控制原理 ..... 11.1.1 并发访问的数据不一致问题 .... 11.1.2 事务以及隔离级别 .. 21.1.3 支持并发的 lock...
oracle动态性能表oracle动态性能表oracle动态性能表
oracle latch介绍,介绍的非常非常非常非常非常非常非常非常非常非常非常非常非常好
确定系统慢的原因: select * from v$session_wait where event != 'client message' and event not like '%NET%' and wait_time = 0 and sid > 5;
以下是对Oracle中Lock与Latch的相同点以及不同点进行了详细的分析介绍,需要的朋友参考下
等待事件row cache lock,latch row cache objects处理过程
有关oracle当中锁的描述,Latch和Lock的区别,挺不错的。
深入解析OracleDBA入门进阶与诊断案例 扫描版 作 者:盖国强 著 出 版 社:人民邮电出版社 出版时间:2009-1-1 页 数:527 内容简介 针对数据库的启动和关闭、控制文件与数据库初始化、参数及参数文件、数据...