锁存器和自旋锁(Latch&Spinlock)----理解Latch和Spinlock

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介:

转载自:http://blog.csdn.net/burgess_liu/article/details/19545473


要理解Latch和Spinlock,你需要知道它们真正的定义以及为什么SQL Server需要它们。

定义

Latch是SQL Server引擎使用的一个内部对象,它不是你能够直接影响得到的。如果你需要从一个特定的页获取数据,SQL Server需要获取一个Latch,对于这一点你别无选择,要获取哪种Latch,也是由SQL  Server引擎决定的。区别就是这不仅关系数据保护,还关系内存保护。即便你愿意容忍脏读,并相应地选择了你的锁策略,你对Latch也没那么奢侈。

Spinlock和Latch的概念类似,因为它也是轻量级同步原语,但它们稍有不同。主要的不同点是,如果一个线程获取Latch失败了,它会立即屈服,使CPU能够用于其他事情。如果一个线程获取Spinlock失败了,线程会开始循环(looping/spinning),重复地检查资源,带着资源立即可用的期望,然而,它不会永远spin,一会儿时间后,它会后退,向CPU上的其他进程屈服。下面将展示模拟的实例。

Latching实例

创建环境:

1
2
3
4
5
6
7
8
9
CREATE  DATABASE  LatchInAction;  
GO  
USE LatchInAction;  
CREATE  TABLE  dbo.LatchTable  
( COL1  INT  
,COL2  INT  
);  
INSERT  INTO  dbo.LatchTable ( COL1, COL2 )  
VALUES  (1,100);

通过命令DBCC IND查看页相关的信息:
wKioL1dqaPOTddOyAABUYAF9slA538.jpg通过PagePID查看页的输出信息:

1
2
DBCC TRACEON(3604);  
DBCC PAGE( 'LatchInAction' ,1,118,1);

wKiom1dqaRqw2EZbAACwj5kByKk009.jpg


输出结果中值得注意的信息有PAGE HEADER中m_slotCnt和m_freeData,DATA中的Slot 0及Length=15,OFFSET TABLE中的Offset 96。这告诉我们页里有一个单行(slot),即Slot 0, 它有15个字节长度,从位置96开始,位置111后面是空的(freedata)。无独有偶,111=96+15。现在通过两个Session分别各插入一笔数据:

1
2
3
4
5
6
     /* TRANSACTION  1 SESSION 1*/  
     INSERT  INTO  LatchTable  
     VALUES  (2,200);  
     /* TRANSACTION  2 SESSION 2*/  
     INSERT  INTO  LatchTable  
     VALUES  (3,300);


两笔插入是并发的,同时被锁管理器接收。两者都不存在行,所以该行没有X锁。两个Session都收到一个页上的IX锁,彼此一致。通过DBCC PAGE再次查看,其输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
PAGE: (1:118)
BUFFER:
BUF @0x0000000080126E40
bpage = 0x00000001E85CC000          bhash = 0x0000000000000000          bpageno = (1:118)
bdbid = 12                          breferences = 0                     bcputicks = 0
bsampleCount = 0                    bUse1 = 9861                        bstat = 0x10b
blog = 0x15a                        bnext = 0x0000000000000000         
PAGE HEADER:
Page @0x00000001E85CC000
m_pageId = (1:118)                  m_headerVersion = 1                 m_type = 1
m_typeFlagBits = 0x0                m_level = 0                         m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 84    m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594043432960                               
Metadata: PartitionId = 72057594039042048                                Metadata: IndexId = 0
Metadata: ObjectId = 245575913      m_prevPage = (0:0)                  m_nextPage = (0:0)
pminlen = 12                        m_slotCnt = 3                       m_freeCnt = 8045
m_freeData = 141                    m_reservedCnt = 0                   m_lsn = (32:252:2)
m_xactReserved = 0                  m_xdesId = (0:0)                    m_ghostRecCnt = 0
m_tornBits = 1862860983             DB Frag ID = 1                     
Allocation Status
GAM (1:2) = ALLOCATED               SGAM (1:3) = ALLOCATED             
PFS (1:1) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                        DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED          
DATA:
Slot 0, Offset 0x60, Length 15, DumpStyle BYTE
Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 15
Memory Dump @0x000000000940A060
0000000000000000:   10000c00 01000000 64000000 020000             ........d......
Slot 1, Offset 0x6f, Length 15, DumpStyle BYTE
Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 15
Memory Dump @0x000000000940A06F
0000000000000000:   10000c00 02000000 c8000000 020000             ...............
Slot 2, Offset 0x7e, Length 15, DumpStyle BYTE
Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 15
Memory Dump @0x000000000940A07E
0000000000000000:   10000c00 03000000 2c010000 020000             ........,......
OFFSET TABLE:
Row - Offset                       
2 (0x2) - 126 (0x7e)               
1 (0x1) - 111 (0x6f)               
0 (0x0) - 96 (0x60)                
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

 当Transaction 1(2,200)到达内存页时,它获取一个latch,这是一个EX Latch。然而片刻之后,Transaction 2(2,300)也想要一个EX Latch,但不能得到。它必须等待Transaction 1完成,你可以在sys.dm_os_wait_stats看到等待。

Transaction 1需要保留EX Latch来完成写入行、更新页头和偏移(offset),在释放Latch之前,它不会等待事务的完成。锁保护事务的完整性,而Latch保护内存的完整性。一旦Transaction 1的Latch释放,3,300事务就会进入,并拥有EX Latch,插入数据行、更行页头及偏移。

没有Latching,数据会丢失;有了latching就不会。不管事务使用哪种隔离级别,SQL Server都会通过Latch保护数据。















本文转自UltraSQL51CTO博客,原文链接:http://blog.51cto.com/ultrasql/1791855 ,如需转载请自行联系原作者


相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
Java 程序员 API
【Lock锁的使用与原理】
【Lock锁的使用与原理】
182 0
|
6月前
|
Linux
【Linux C 几种锁的性能对比】 1.读写锁 2.互斥锁 3.自旋锁 4.信号量 5.rcu
【Linux C 几种锁的性能对比】 1.读写锁 2.互斥锁 3.自旋锁 4.信号量 5.rcu
自旋锁是啥?
自旋锁是一种基于忙等待的锁机制,它允许线程反复检测锁状态,而不是阻塞等待。当线程尝试获取一个自旋锁时,如果锁已经被其他线程持有,该线程会一直在一个循环中自旋,直到锁被释放。
59 0
|
Linux 程序员 API
|
安全 Java
多线程详解p18、Lock锁
多线程详解p18、Lock锁
|
API 数据安全/隐私保护
Lock锁
Lock锁
146 0
Lock锁
自旋锁和互斥锁区别
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/81057190 POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API。
1082 0