日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

postgresql源码学习(十三)—— 行锁①-行锁模式与xmax

發(fā)布時間:2024/3/13 编程问答 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 postgresql源码学习(十三)—— 行锁①-行锁模式与xmax 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、 四種行鎖?

1. 簡介與兼容性分析

? ? ? ?pg采用元組級常規(guī)鎖+xmax結(jié)合的方式實現(xiàn)行鎖。我們曾經(jīng)提到過常規(guī)鎖是有很多類TAG的(typedef enum LockTagType),其中 LOCKTAG_TUPLE就是用來對元組加鎖的。

? ? ? ?不單純用元組級常規(guī)鎖,是為了避免事務修改行過多時,鎖表急劇增大導致性能劣化,并且鎖表在共享內(nèi)存中的大小是有限的。因此,行鎖是不存儲在內(nèi)存中的。

pg中通常有兩種方式會用到行鎖:

  • 對行執(zhí)行update,delete操作
  • 顯式指定行鎖(例如select for update)

在新版本中,顯式加行鎖共有4種寫法

行鎖類型

簡介

FOR UPDATE

FOR UPDATE會鎖定SELECT檢索到的行,就好像它們要被更新。

這可以阻止它們被其他事務鎖定、修改或者刪除,直到當前事務結(jié)束。

DELETE和修改主鍵、唯一鍵值的UPDATE會獲得這種鎖模式。

FOR NO KEY UPDATE

行為與FOR UPDATE類似,不過獲得的鎖較弱,不會阻塞SELECT FOR KEY SHARE。

不修改主鍵、唯一鍵值的UPDATE會獲得這種鎖模式。

FOR SHARE

行為與FOR NO KEY UPDATE類似,不過它在每個檢索到的行上獲得一個共享鎖而不是排他鎖。

讀該行,不允許對行進行更新

FOR KEY SHARE

行為與FOR SHARE類似,不過鎖更弱,不會被SELECT
FOR NO KEY UPDATE阻塞。

讀該行鍵值,但允許對除鍵外的其他字段更新。在外鍵檢查時使用該鎖

4種行鎖兼容性如下

4種行鎖兼容性如下

詳細可參考 ?官方文檔第13章 13.3.2. Row-Level Locks

2. 對應源碼

它們對應的源碼在lockoptions.h文件

/** Possible lock modes for a tuple.*/ typedef enum LockTupleMode {/* SELECT FOR KEY SHARE */LockTupleKeyShare,/* SELECT FOR SHARE */LockTupleShare,/* SELECT FOR NO KEY UPDATE, and UPDATEs that don't modify key columns */LockTupleNoKeyExclusive,/* SELECT FOR UPDATE, UPDATEs that modify key columns, and DELETE */LockTupleExclusive } LockTupleMode;

? ? ? ?如前所述,pg行鎖是由常規(guī)鎖+xmax結(jié)合實現(xiàn)的,因此它需要建立常規(guī)鎖與LockTupleMode之間的映射關(guān)系。

/** Each tuple lock mode has a corresponding heavyweight lock, and one or two* corresponding MultiXactStatuses (one to merely lock tuples, another one to* update them). This table (and the macros below) helps us determine the* heavyweight lock mode and MultiXactStatus values to use for any particular* tuple lock strength.** Don't look at lockstatus/updstatus directly! Use get_mxact_status_for_lock* instead.*/ static const struct {LOCKMODE hwlock; // 對應的常規(guī)鎖模式int lockstatus; // 顯式指定的鎖模式int updstatus; // 隱式指定的鎖模式 }tupleLockExtraInfo[MaxLockTupleMode + 1] = {{ /* LockTupleKeyShare */AccessShareLock, // 1級表鎖MultiXactStatusForKeyShare,-1 /* KeyShare does not allow updating tuples */},{ /* LockTupleShare */RowShareLock, // 2級表鎖MultiXactStatusForShare,-1 /* Share does not allow updating tuples */},{ /* LockTupleNoKeyExclusive */ExclusiveLock, // 7級表鎖MultiXactStatusForNoKeyUpdate,MultiXactStatusNoKeyUpdate},{ /* LockTupleExclusive */AccessExclusiveLock, // 8級表鎖MultiXactStatusForUpdate,MultiXactStatusUpdate} };

? ? ? ? 其實這些行鎖模式的兼容性是怎么來的,就是根據(jù)對應的表鎖兼容性來的。例如一個delete操作,它在表上加的是3級鎖,但在行上加的是8級鎖。因此在表上該操作是兼容的(可以同時對一個表進行delete),但在行上是沖突的(不可以同時delete同一行)。

二、 xmax的設(shè)置

? ? ? ?通過前面的源碼可以看到,tupleLockExtraInfo中除了保存常規(guī)鎖對應的鎖模式,還保存了大量MultiXact中的鎖模式,MultiXact又是個什么呢?

1. MultiXactId

? ? ? ?通常如果只有一個事務增加行鎖,那么直接將行的xmax設(shè)為事務id,并在infomask中設(shè)置對應鎖類型即可。

? ? ? ?但select…for…語句中可以加行級共享鎖,即可以有多個事務對一個元組加共享鎖,這時就沒法通過將行的xmax設(shè)為事務id來表示了。為此,pg將多個事務組成一個mXactCacheEnt(multixact.c文件),并為其指定唯一的MultiXactId,此時在xmax處保存的就是MultiXactId。

typedef struct mXactCacheEnt {MultiXactId multi;int nmembers;dlist_node node;MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]; } mXactCacheEnt;

? ?為了區(qū)分xmax設(shè)置的是事務id還是MultiXactId,在使用MultiXactId時會在元組上增加HEAP_XMAX_IS_MULTI標記。

2. 模擬案例

會話1

create table t1(a int primary key,b int); insert into t1 values(1,1); select xmin,xmax,* from t1; -- 事務id 761

會話2

Begin; select * from t1 for key share; -- 事務不提交

會話1

select xmin,xmax,* from t1; -- 當前xmax中保存的是事務id(762)

會話3

Begin; select * from t1 for share; -- 事務不提交(事務id 763)

會話1

select xmin,xmax,* from t1; -- 當前xmax中保存的是MultiXactId

怎么知道這個是MultiXactId?可以通過控制文件查看

pg_controldata –D $PGDATA | grep Multi

3. 行鎖標記位

  • 如果元組的xmax是事務id,需要通過infomask標記位區(qū)分元組的加鎖情況。

源代碼在htup_details.h,其實有很多種狀態(tài),這里只簡單列一些

#define HEAP_XMAX_KEYSHR_LOCK 0x0010 /* for key share子句對應的鎖 */ #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker,排他鎖標記位 */ /* xmax is a shared locker */ #define HEAP_XMAX_SHR_LOCK (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK) #define HEAP_XMAX_LOCK_ONLY 0x0080 /* xmax, if valid, is only a locker,顯式加行鎖 */ #define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */ #define HEAP_KEYS_UPDATED 0x2000 /* tuple was updated and key cols */

詳細可參考 ?https://mp.weixin.qq.com/s/nDBYbJpoBVqZxpYYaxPZ6Q

  • 如果元組的xmax是MultiXactId,則每種子句都對應一種鎖模式(它們的對應關(guān)系通過tupleLockExtraInfo也可以看出來)
/** Possible multixact lock modes ("status"). The first four modes are for* tuple locks (FOR KEY SHARE, FOR SHARE, FOR NO KEY UPDATE, FOR UPDATE); the* next two are used for update and delete modes.*/ typedef enum {MultiXactStatusForKeyShare = 0x00,MultiXactStatusForShare = 0x01,MultiXactStatusForNoKeyUpdate = 0x02,MultiXactStatusForUpdate = 0x03,/* an update that doesn't touch "key" columns */MultiXactStatusNoKeyUpdate = 0x04,/* other updates, and delete */MultiXactStatusUpdate = 0x05 } MultiXactStatus;

? ? ? ?為了保存MultiXactId和事務的映射關(guān)系,pg使用兩個SLRU進行分層映射,它們位于$PGDATA/pg_multixact目錄下,分別是offsets目錄和members目錄。

參考

《PostgreSQL技術(shù)內(nèi)幕:事務處理深度探索》第2章

PostgreSQL鎖機制——行級鎖 - JavaShuo

https://www.modb.pro/db/70021

https://www.modb.pro/video/5128?sjhy

總結(jié)

以上是生活随笔為你收集整理的postgresql源码学习(十三)—— 行锁①-行锁模式与xmax的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。