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


转载自: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实例

创建环境:

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查看页相关的信息:
锁存器和自旋锁(Latch&Spinlock)----理解Latch和Spinlock_第1张图片通过PagePID查看页的输出信息:

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

锁存器和自旋锁(Latch&Spinlock)----理解Latch和Spinlock_第2张图片


输出结果中值得注意的信息有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分别各插入一笔数据:

    /*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再次查看,其输出如下:

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保护数据。