国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入解析 PostgreSQL 系列之并發(fā)控制與事務(wù)機(jī)制

JohnLui / 2210人閱讀

摘要:深入解析系列之并發(fā)控制與事務(wù)機(jī)制并發(fā)控制旨在針對(duì)數(shù)據(jù)庫(kù)中對(duì)事務(wù)并行的場(chǎng)景,保證中的一致性與隔離。啟動(dòng)并執(zhí)行第一個(gè)命令。事務(wù)管理器分配,并返回事務(wù)快照,因?yàn)檎谶M(jìn)行中。意味著該行由另一個(gè)并發(fā)事務(wù)更新,并且其事務(wù)尚未終止。

深入解析 PostgreSQL 系列整理自 The Internals of PostgreSQL 等系列文章,從碎片化地閱讀到體系化地學(xué)習(xí),感覺對(duì)數(shù)據(jù)庫(kù)有了更深入地了解;觸類旁通,相互印證,也是有利于掌握 MySQL 等其他的關(guān)系型數(shù)據(jù)庫(kù)或者 NoSQL 數(shù)據(jù)庫(kù)。
深入解析 PostgreSQL 系列之并發(fā)控制與事務(wù)機(jī)制

并發(fā)控制旨在針對(duì)數(shù)據(jù)庫(kù)中對(duì)事務(wù)并行的場(chǎng)景,保證 ACID 中的一致性(Consistency)與隔離(Isolation)。數(shù)據(jù)庫(kù)技術(shù)中主流的三種并發(fā)控制技術(shù)分別是: Multi-version Concurrency Control (MVCC), Strict Two-Phase Locking (S2PL), 以及 Optimistic Concurrency Control (OCC),每種技術(shù)也都有很多的變種。在 MVCC 中,每次寫操作都會(huì)在舊的版本之上創(chuàng)建新的版本,并且會(huì)保留舊的版本。當(dāng)某個(gè)事務(wù)需要讀取數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)系統(tǒng)會(huì)從所有的版本中選取出符合該事務(wù)隔離級(jí)別要求的版本。MVCC 的最大優(yōu)勢(shì)在于讀并不會(huì)阻塞寫,寫也不會(huì)阻塞讀;而像 S2PL 這樣的系統(tǒng),寫事務(wù)會(huì)事先獲取到排他鎖,從而會(huì)阻塞讀事務(wù)。

PostgreSQL 以及 Oracle 等 RDBMS 實(shí)際使用了所謂的 Snapshot Isolation(SI)這個(gè) MVCC 技術(shù)的變種。Oracle 引入了額外的 Rollback Segments,當(dāng)寫入新的數(shù)據(jù)時(shí),老版本的數(shù)據(jù)會(huì)被寫入到 Rollback Segment 中,隨后再被覆寫到實(shí)際的數(shù)據(jù)塊。PostgreSQL 則是使用了相對(duì)簡(jiǎn)單的實(shí)現(xiàn)方式,新的數(shù)據(jù)對(duì)象會(huì)被直接插入到關(guān)聯(lián)的 Table Page 中;而在讀取表數(shù)據(jù)的時(shí)候,PostgreSQL 會(huì)通過(guò)可見性檢測(cè)規(guī)則(Visibility Check Rules)來(lái)選擇合適的版本。

SI 能夠避免 ANSI SQL-92 標(biāo)準(zhǔn)中定義的三個(gè)反常現(xiàn)象:臟讀(Dirty Reads),不可重復(fù)讀(Non-Repeatable Reads)以及幻讀(Phantom Reads);在 9.1 版本后引入的 Serializable Snapshot Isolation(SSI)則能夠提供真正的順序讀寫的能力。

Isolation Level Dirty Reads Non-repeatable Read Phantom Read Serialization Anomaly
READ COMMITTED Not possible Possible Possible Possible
REPEATABLE READ Not possible Not possible Not possible in PG; See Section 5.7.2. (Possible in ANSI SQL) Possible
SERIALIZABLE Not possible Not possible Not possible Not possible
Tuple 結(jié)構(gòu) Transaction ID

當(dāng)某個(gè)事務(wù)開啟時(shí),PostgreSQL 內(nèi)置的 Transaction Manager 會(huì)為它分配唯一的 Transaction ID(txid);txid 是 32 位無(wú)類型整型值,可以通過(guò) txid_current() 函數(shù)來(lái)獲取當(dāng)前的 txid:

testdb=# BEGIN;
BEGIN
testdb=# SELECT txid_current();
 txid_current
--------------
          100
(1 row)

PostgreSQL 還保留了三個(gè)關(guān)鍵 txid 值作特殊標(biāo)記:0 表示無(wú)效的 txid,1 表示啟動(dòng)時(shí)的 txid,僅在 Database Cluster 啟動(dòng)時(shí)使用;2 代表了被凍結(jié)的(Frozen)txid,用于在序列化事務(wù)時(shí)候使用。PostgreSQL 選擇數(shù)值類型作為 txid,也是為了方便進(jìn)行比較;對(duì)于 txid 值為 100 的事務(wù)而言,所有小于 100 的事務(wù)是發(fā)生在過(guò)去的,可見的;而所有大于 100 的事務(wù),是發(fā)生在未來(lái),即不可見的。

鑒于實(shí)際系統(tǒng)中的 txid 數(shù)目的需要可能會(huì)超過(guò)最大值,PostgreSQL 實(shí)際是將這些 txid 作為環(huán)來(lái)看待。

HeapTupleHeaderData

Table Pages 中的 Heap Tuples 往往包含三個(gè)部分:HeapTupleHeaderData 結(jié)構(gòu),NULL bitmap 以及用戶數(shù)據(jù)。

其中 HeapTupleHeaderData 與事物處理強(qiáng)相關(guān)的屬性有:

(TransactionId)t_xmin: 存放插入該 Tuple 時(shí)的 txid

(TransactionId)t_xmax: 存放刪除或者更新該 Tuple 時(shí)的 txid,如果還沒更新或者刪除,那么置 0,表示無(wú)效

(CommandId)t_cid: 存放 Command ID,即 創(chuàng)建該 Tuple 的命令在該事務(wù)內(nèi)執(zhí)行的所有 SQL 命令中的編號(hào);譬如 BEGIN; INSERT; INSERT; INSERT; COMMIT; 這個(gè)事務(wù),如果是首個(gè) INSERT 命令創(chuàng)建的 Tuple,那么其 t_cid 值為 0,第二個(gè)就是 1

(ItemPointerData)t_ctid: 當(dāng)某個(gè) Tuple 更新時(shí),該值就指向新創(chuàng)建的 Tuple,否則指向自己

Tuple 的插入、刪除與更新

如上所述,Table Pages 中的 Tuples 呈如下布局:

插入

在執(zhí)行插入操作時(shí),PostgreSQL 會(huì)直接將某個(gè)新的 Tuple 插入到目標(biāo)表的某個(gè)頁(yè)中:

假如某個(gè) txid 為 99 的事務(wù)插入了新的 Tuple,那么該 Tuple 的頭域會(huì)被設(shè)置為如下值:

t_xmin 與創(chuàng)建該 Tuple 的事務(wù)的 txid 保持一致,即 99

t_xmax 被設(shè)置為 0,因?yàn)槠溥€未被刪除或者更新

t_cid 被設(shè)置為 0,因?yàn)樵?Tuple 是由事務(wù)中的首個(gè) Insert 命令創(chuàng)建的

t_ctid 被設(shè)置為了 (0, 1),即指向了自己

testdb=# CREATE EXTENSION pageinspect;
CREATE EXTENSION
testdb=# CREATE TABLE tbl (data text);
CREATE TABLE
testdb=# INSERT INTO tbl VALUES("A");
INSERT 0 1
testdb=# SELECT lp as tuple, t_xmin, t_xmax, t_field3 as t_cid, t_ctid
                FROM heap_page_items(get_raw_page("tbl", 0));
 tuple | t_xmin | t_xmax | t_cid | t_ctid
-------+--------+--------+-------+--------
     1 |     99 |      0 |     0 | (0,1)
刪除

在刪除操作中,目標(biāo) Tuple 會(huì)被先邏輯刪除,即將 t_xmax 的值設(shè)置為當(dāng)前刪除該 Tuple 的事務(wù)的 txid 值。

當(dāng)該事務(wù)被提交之后,PostgreSQL 會(huì)將該 Tuple 標(biāo)記為 Dead Tuple,并隨后在 VACUUM 處理過(guò)程中被徹底清除。

更新

在更新操作時(shí),PostgreSQL 會(huì)首先邏輯刪除最新的 Tuple,然后插入新的 Tuple:

上圖所示的行被 txid 為 99 的事務(wù)插入,被 txid 為 100 的事務(wù)連續(xù)更新兩次;在該事務(wù)提交之后,Tuple_2 與 Tuple_3 就會(huì)被標(biāo)記為 Dead Tuples。

Free Space Map

當(dāng)插入某個(gè) Heap Tuple 或者 Index Tuple 時(shí),PostgreSQL 使用相關(guān)表的 FSM 來(lái)決定應(yīng)該選擇哪個(gè) Page 來(lái)進(jìn)行具體的插入操作。每個(gè) FSM 都存放著表或者索引文件相關(guān)的剩余空間容量的信息,可以使用如下方式查看:

testdb=# CREATE EXTENSION pg_freespacemap;
CREATE EXTENSION

testdb=# SELECT *, round(100 * avail/8192 ,2) as "freespace ratio"
                FROM pg_freespace("accounts");
 blkno | avail | freespace ratio
-------+-------+-----------------
     0 |  7904 |           96.00
     1 |  7520 |           91.00
     2 |  7136 |           87.00
     3 |  7136 |           87.00
     4 |  7136 |           87.00
     5 |  7136 |           87.00
....
Commit Log

PostgreSQL 使用 Commit Log,亦稱 clog 來(lái)存放事務(wù)的狀態(tài);clog 存放于 Shared Memory 中,在整個(gè)事務(wù)處理的生命周期中都起到了重要的作用。PostgreSQL 定義了四種不同的事務(wù)狀態(tài):IN_PROGRESS, COMMITTED, ABORTED, 以及 SUB_COMMITTED。

Clog 有 Shared Memory 中多個(gè) 8KB 大小的頁(yè)構(gòu)成,其邏輯上表現(xiàn)為類數(shù)組結(jié)構(gòu),數(shù)組下標(biāo)即是關(guān)聯(lián)的事務(wù)的 txid,而值就是當(dāng)前事務(wù)的狀態(tài):

如果當(dāng)前的 txid 超過(guò)了當(dāng)前 clog 頁(yè)可承載的最大范圍,那么 PostgreSQL 會(huì)自動(dòng)創(chuàng)建新頁(yè)。而在 PostgreSQL 停止或者 Checkpoint 進(jìn)程運(yùn)行的時(shí)候,clog 的數(shù)據(jù)會(huì)被持久化存儲(chǔ)到 pg_xact 子目錄下,以 0000,0001 依次順序命名,單個(gè)文件的最大尺寸為 256KB。而當(dāng) PostgreSQL 重啟的時(shí)候,存放在 pg_xact 目錄下的文件會(huì)被重新加載到內(nèi)存中。而隨著 PostgreSQL 的持續(xù)運(yùn)行,clog 中勢(shì)必會(huì)累計(jì)很多的過(guò)時(shí)或者無(wú)用的數(shù)據(jù),Vacuum 處理過(guò)程中同樣會(huì)清除這些無(wú)用的數(shù)據(jù)。

Transaction Snapshot | 事務(wù)快照

事務(wù)快照即是存放了當(dāng)前全部事務(wù)是否為激活狀態(tài)信息的數(shù)據(jù)結(jié)構(gòu),PostgreSQL 內(nèi)部將快照表示為簡(jiǎn)單的文本結(jié)構(gòu),xmin:xmax:xip_list’;譬如 "100",其意味著所有 txid 小于或者等于 99 的事務(wù)是非激活狀態(tài),而大于等于 100 的事務(wù)是處在了激活狀態(tài)。

testdb=# SELECT txid_current_snapshot();
 txid_current_snapshot
-----------------------
 100:104:100,102
(1 row)

xmin: 最早的仍處在激活狀態(tài)的 txid,所有更早之前的事務(wù)要么處于被提交之后的可見態(tài),要么就是被回滾之后的假死態(tài)。

xmax: 首個(gè)至今仍未分配的事務(wù)編號(hào),所有 txid 大于或者等于該值的事務(wù),相對(duì)于該快照歸屬的事務(wù)都是尚未發(fā)生的,因此是不可見的。

xip_list: 快照時(shí)候處于激活狀態(tài)的 txids,僅會(huì)包含在 xmin 與 xmax 之間的 txids。

100:104:100,102 為例,其示意圖如下所示:

事務(wù)快照主要由事務(wù)管理器(Transaction Manager)提供,在 READ COMMITTED 這個(gè)隔離級(jí)別,無(wú)論是否有 SQL 命令執(zhí)行,該事務(wù)都會(huì)被分配到某個(gè)快照;而對(duì)于 REPEATABLE READ 或者 SERIALIZABLE 隔離級(jí)別的事務(wù)而言,僅當(dāng)首個(gè) SQL 語(yǔ)句被執(zhí)行的時(shí)候,才會(huì)被分配到某個(gè)事務(wù)快照用于進(jìn)行可見性檢測(cè)。事務(wù)快照的意義在于,當(dāng)某個(gè)快照進(jìn)行可見性判斷時(shí),無(wú)論目標(biāo)事務(wù)是否已經(jīng)被提交或者放棄,只要他在快照中被標(biāo)記為 Active,那么其就會(huì)被當(dāng)做 IN_PROGRESS 狀態(tài)的事務(wù)來(lái)處理。

事務(wù)管理器始終保存有關(guān)當(dāng)前運(yùn)行的事務(wù)的信息。假設(shè)三個(gè)事務(wù)一個(gè)接一個(gè)地開始,并且 Transaction_A 和 Transaction_B 的隔離級(jí)別是 READ COMMITTED,Transaction_C 的隔離級(jí)別是 REPEATABLE READ。

T1:

Transaction_A 啟動(dòng)并執(zhí)行第一個(gè) SELECT 命令。執(zhí)行第一個(gè)命令時(shí),Transaction_A 請(qǐng)求此刻的 txid 和快照。在這種情況下,事務(wù)管理器分配 txid 200,并返回事務(wù)快照"200:200:"。

T2:

Transaction_B 啟動(dòng)并執(zhí)行第一個(gè) SELECT 命令。事務(wù)管理器分配 txid 201,并返回事務(wù)快照"200:200:",因?yàn)?Transaction_A(txid 200)正在進(jìn)行中。因此,無(wú)法從 Transaction_B 中看到 Transaction_A。

T3:

Transaction_C 啟動(dòng)并執(zhí)行第一個(gè) SELECT 命令。事務(wù)管理器分配 txid 202,并返回事務(wù)快照"200:200:",因此,Transaction_A 和 Transaction_B 不能從 Transaction_C 中看到。

T4:

Transaction_A 已提交。事務(wù)管理器刪除有關(guān)此事務(wù)的信息。

T5:

Transaction_B 和 Transaction_C 執(zhí)行各自的 SELECT 命令。

Transaction_B 需要事務(wù)快照,因?yàn)樗幱?READ COMMITTED 級(jí)別。在這種情況下,Transaction_B 獲取新快照"201:201:",因?yàn)?Transaction_A(txid 200)已提交。因此,Transaction_B 不再是 Transaction_B 中不可見的。

Transaction_C 不需要事務(wù)快照,因?yàn)樗幱?REPEATABLE READ 級(jí)別并使用獲得的快照,即"200:200:"。因此,Transaction_A 仍然是 Transaction_C 不可見的。

Visibility Check | 可見性檢測(cè) Rules | 可見性檢測(cè)規(guī)則

可見性檢測(cè)的規(guī)則用于根據(jù) Tuple 的 t_xmin 與 t_xmax,clog 以及自身分配到的事務(wù)快照來(lái)決定某個(gè) Tuple 相對(duì)于某個(gè)事務(wù)是否可見。

t_xmin 對(duì)應(yīng)事務(wù)的狀態(tài)為 ABORTED

當(dāng)某個(gè) Tuple 的 t_xmin 值對(duì)應(yīng)的事務(wù)的狀態(tài)為 ABORTED 時(shí)候,該 Tuple 永遠(yuǎn)是不可見的:

/* t_xmin status = ABORTED */
// Rule 1: If Status(t_xmin) = ABORTED ? Invisible
Rule 1: IF t_xmin status is "ABORTED" THEN
                  RETURN "Invisible"
            END IF
t_xmin 對(duì)應(yīng)事務(wù)的狀態(tài)為 IN_PROGRESS

對(duì)于非插入該 Tuple 的事務(wù)之外的其他事務(wù)關(guān)聯(lián)的 Tuple 而言,該 Tuple 永遠(yuǎn)是不可見的;僅對(duì)于與該 Tuple 同屬一事務(wù)的 Tuple 可見(此時(shí)該 Tuple 未被刪除或者更新的)。

 /* t_xmin status = IN_PROGRESS */
              IF t_xmin status is "IN_PROGRESS" THEN
                   IF t_xmin = current_txid THEN
// Rule 2: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax = INVAILD ? Visible
Rule 2:              IF t_xmax = INVALID THEN
                  RETURN "Visible"
// Rule 3: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax ≠ INVAILD ? Invisible

Rule 3:              ELSE  /* this tuple has been deleted or updated by the current transaction itself. */
                  RETURN "Invisible"
                         END IF
// Rule 4: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin ≠ current_txid ? Invisible
Rule 4:        ELSE   /* t_xmin ≠ current_txid */
                  RETURN "Invisible"
                   END IF
             END IF
t_xmin 對(duì)應(yīng)事務(wù)的狀態(tài)為 COMMITTED

此時(shí)該 Tuple 在大部分情況下都是可見的,除了該 Tuple 被更新或者刪除。

 /* t_xmin status = COMMITTED */
            IF t_xmin status is "COMMITTED" THEN
//  If Status(t_xmin) = COMMITTED ∧ Snapshot(t_xmin) = active ? Invisible
Rule 5:      IF t_xmin is active in the obtained transaction snapshot THEN
                      RETURN "Invisible"
// If Status(t_xmin) = COMMITTED ∧ (t_xmax = INVALID ∨ Status(t_xmax) = ABORTED) ? Visible
Rule 6:      ELSE IF t_xmax = INVALID OR status of t_xmax is "ABORTED" THEN
                      RETURN "Visible"
                 ELSE IF t_xmax status is "IN_PROGRESS" THEN
// If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax = current_txid ? Invisible
Rule 7:           IF t_xmax =  current_txid THEN
                            RETURN "Invisible"
// If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax ≠ current_txid ? Visible
Rule 8:           ELSE  /* t_xmax ≠ current_txid */
                            RETURN "Visible"
                      END IF
                 ELSE IF t_xmax status is "COMMITTED" THEN
// If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) = active ? Visible
Rule 9:           IF t_xmax is active in the obtained transaction snapshot THEN
                            RETURN "Visible"
// If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) ≠ active ? Invisible
Rule 10:         ELSE
                            RETURN "Invisible"
                      END IF
                 END IF
            END IF
可見性檢測(cè)流程

以簡(jiǎn)單的雙事務(wù)更新與查詢?yōu)槔?/p>

上圖中 txid 200 的事務(wù)的隔離級(jí)別是 READ COMMITED,txid 201 的隔離級(jí)別為 READ COMMITED 或者 REPEATABLE READ。

當(dāng)在 T3 時(shí)刻執(zhí)行 SELECT 命令時(shí):

根據(jù) Rule 6,此時(shí)僅有 Tuple_1 是處于可見狀態(tài):

# Rule6(Tuple_1) ? Status(t_xmin:199) = COMMITTED ∧ t_xmax = INVALID ? Visible

testdb=# -- txid 200
testdb=# SELECT * FROM tbl;
  name
--------
 Jekyll
(1 row)

testdb=# -- txid 201
testdb=# SELECT * FROM tbl;
  name
--------
 Jekyll
(1 row)

當(dāng)在 T5 時(shí)刻執(zhí)行 SELECT 命令時(shí):

對(duì)于 txid 200 的事務(wù)而言,根據(jù) Rule 7 與 Rule 2 可知,Tuple_1 可見而 Tuple_2 不可見:

# Rule7(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = IN_PROGRESS ∧ t_xmax:200 = current_txid:200 ? Invisible
# Rule2(Tuple_2): Status(t_xmin:200) = IN_PROGRESS ∧ t_xmin:200 = current_txid:200 ∧ t_xmax = INVAILD ? Visible

testdb=# -- txid 200
testdb=# SELECT * FROM tbl;
 name
------
 Hyde
(1 row)

而對(duì)于 txid 201 的事務(wù)而言,Tuple_1 是可見的,Tuple_2 是不可見的:

# Rule8(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = IN_PROGRESS ∧ t_xmax:200 ≠ current_txid:201 ? Visible
# Rule4(Tuple_2): Status(t_xmin:200) = IN_PROGRESS ∧ t_xmin:200 ≠ current_txid:201 ? Invisible

testdb=# -- txid 201
testdb=# SELECT * FROM tbl;
  name
--------
 Jekyll
(1 row)

當(dāng)在 T7 時(shí)刻執(zhí)行 SELECT 命令時(shí):

如果此時(shí) txid 201 的事務(wù)處于 READ COMMITED 的隔離級(jí)別,那么 txid 200 會(huì)被當(dāng)做 COMMITTED 來(lái)處理,因?yàn)榇藭r(shí)獲取到的事務(wù)快照是 201:201:,因此 Tuple_1 是不可見的,而 Tuple_2 是可見的:

# Rule10(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = COMMITTED ∧ Snapshot(t_xmax:200) ≠ active ? Invisible
# Rule6(Tuple_2): Status(t_xmin:200) = COMMITTED ∧ t_xmax = INVALID ? Visible

testdb=# -- txid 201 (READ COMMITTED)
testdb=# SELECT * FROM tbl;
 name
------
 Hyde
(1 row)

如果此時(shí) txid 201 的事務(wù)處于 REPEATABLE READ 的隔離級(jí)別,此時(shí)獲取到的事務(wù)快照還是 200:200:,那么 txid 200 的事務(wù)必須被當(dāng)做 IN_PROGRESS 狀態(tài)來(lái)處理;因此此時(shí) Tuple_1 是可見的,而 Tuple_2 是不可見的:

# Rule9(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = COMMITTED ∧ Snapshot(t_xmax:200) = active ? Visible
# Rule5(Tuple_2): Status(t_xmin:200) = COMMITTED ∧ Snapshot(t_xmin:200) = active ? Invisible

testdb=# -- txid 201 (REPEATABLE READ)
testdb=# SELECT * FROM tbl;
  name
--------
 Jekyll
(1 row)
Preventing Lost Updates | 避免更新丟失

所謂的 更新丟失(Lost Update),也就是寫沖突(ww-conflict),其出現(xiàn)在兩個(gè)事務(wù)同時(shí)更新相同的行;在 PostgreSQL 中,REPEATABLE READ 與 SERIALIZABLE 這兩個(gè)級(jí)別都需要規(guī)避這種異常現(xiàn)象。

(1)  FOR each row that will be updated by this UPDATE command
(2)       WHILE true

               /* The First Block */
(3)            IF the target row is being updated THEN
(4)                  WAIT for the termination of the transaction that updated the target row

(5)                  IF (the status of the terminated transaction is COMMITTED)
                          AND (the isolation level of this transaction is REPEATABLE READ or SERIALIZABLE) THEN
(6)                           ABORT this transaction  /* First-Updater-Win */
                  ELSE
(7)                           GOTO step (2)
                  END IF

               /* The Second Block */
(8)            ELSE IF the target row has been updated by another concurrent transaction THEN
(9)                  IF (the isolation level of this transaction is READ COMMITTED THEN
(10)                           UPDATE the target row
                  ELSE
(11)                           ABORT this transaction  /* First-Updater-Win */
                  END IF

               /* The Third Block */
                ELSE  /* The target row is not yet modified or has been updated by a terminated transaction. */
(12)                  UPDATE the target row
                END IF
           END WHILE
      END FOR

在上述流程中,UPDATE 命令會(huì)遍歷每個(gè)待更新行,當(dāng)發(fā)現(xiàn)該行正在被其他事務(wù)更新時(shí)進(jìn)入等待狀態(tài)直到該行被解除鎖定。如果該行已經(jīng)被更新,并且隔離級(jí)別為 REPEATABLE 或者 SERIALIZABLE,則放棄更新。

Being updated 意味著該行由另一個(gè)并發(fā)事務(wù)更新,并且其事務(wù)尚未終止。因?yàn)?PostgreSQL 的 SI 使用 first-updater-win 方案, 在這種情況下,當(dāng)前事務(wù)必須等待更新目標(biāo)行的事務(wù)的終止。假設(shè)事務(wù) Tx_A 和 Tx_B 同時(shí)運(yùn)行,并且 Tx_B 嘗試更新行;但是 Tx_A 已更新它并且仍在進(jìn)行中,Tx_B 等待 Tx_A 的終止。在更新目標(biāo)行提交的事務(wù)之后,繼續(xù)當(dāng)前事務(wù)的更新操作。 如果當(dāng)前事務(wù)處于 READ COMMITTED 級(jí)別,則將更新目標(biāo)行; 否則 REPEATABLE READ 或 SERIALIZABLE,當(dāng)前事務(wù)立即中止以防止丟失更新。

空間整理

PostgreSQL 的并發(fā)控制機(jī)制還依賴于以下的維護(hù)流程:

移除那些被標(biāo)記為 Dead 的 Tuples 與 Index Tuples

移除 clog 中過(guò)時(shí)的部分

凍結(jié)舊的 txids

更新 FSM,VM 以及其他統(tǒng)計(jì)信息

首先討論下 txid 環(huán)繞式處理的問題,假設(shè) txid 100 的事務(wù)插入了某個(gè) Tuple_1,則該 Tuple 對(duì)應(yīng)的 t_xmin 值為 100;而后服務(wù)器又運(yùn)行了許久,Tuple_1 期間并未被改變。直到 txid 為 2^31 + 101 時(shí),對(duì)于該事務(wù)而言,其執(zhí)行 SELECT 命令時(shí),是無(wú)法看到 Tuple_1 的 ,因?yàn)?txid 為 100 的事務(wù)相對(duì)于其是發(fā)生在未來(lái)的,由其創(chuàng)建的 Tuple 自然也就是不可見的。

為了解決這個(gè)問題,PostgreSQL 引入了所謂的 frozen txid(被凍結(jié)的 txid),并且設(shè)置了 FREEZE 進(jìn)程來(lái)具體處理該問題。前文提及到 txid 2 是保留值,專門表征那些被凍結(jié)的 Tuple,這些 Tuple 永遠(yuǎn)是非激活的、可見的。FREEZE 進(jìn)程同樣由 Vacuum 進(jìn)程統(tǒng)一調(diào)用,它會(huì)掃描所有的表文件,將那些與當(dāng)前 txid 差值超過(guò) vacuum_freeze_min_age 定義的 Tuple 的 t_xmin 域設(shè)置為 2。在 9.4 版本之后,則是將 t_infomask 域中的 XMIN_FROZEN 位設(shè)置來(lái)表征該 Tuple 為凍結(jié)狀態(tài)。

延伸閱讀

如果希望深入淺出 分布式系統(tǒng),分布式計(jì)算,分布式存儲(chǔ),數(shù)據(jù)庫(kù),操作系統(tǒng),虛擬化 等內(nèi)容,可以參閱 深入淺出分布式基礎(chǔ)架構(gòu), DistributedSystem CheatSheet, Database CheatSheet, Linux CheatSheet, MySQL CheatSheet, Docker CheatSheet, Flink CheatSheet, Kafka CheatSheet 等。

如果想獲取分布式系統(tǒng)、虛擬化調(diào)度、數(shù)據(jù)庫(kù)、分布式存儲(chǔ)、分布式計(jì)算、操作系統(tǒng)等領(lǐng)域更多資料: Docker List, Kubernetes List, Linux List, HTTP List, Distributed System List, Blockchain List, Flink List, Kafka List, Database List, MySQL List, PostgreSQL List, etc.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/39008.html

相關(guān)文章

  • 深入解析 PostgreSQL 系列并發(fā)控制事務(wù)機(jī)制

    摘要:深入解析系列之并發(fā)控制與事務(wù)機(jī)制并發(fā)控制旨在針對(duì)數(shù)據(jù)庫(kù)中對(duì)事務(wù)并行的場(chǎng)景,保證中的一致性與隔離。啟動(dòng)并執(zhí)行第一個(gè)命令。事務(wù)管理器分配,并返回事務(wù)快照,因?yàn)檎谶M(jìn)行中。意味著該行由另一個(gè)并發(fā)事務(wù)更新,并且其事務(wù)尚未終止。 showImg(https://segmentfault.com/img/remote/1460000018081793); 深入解析 PostgreSQL 系列整理...

    leone 評(píng)論0 收藏0
  • database

    摘要:它是第一個(gè)把數(shù)據(jù)分布在全球范圍內(nèi)的系統(tǒng),并且支持外部一致性的分布式事務(wù)。目的是使得開發(fā)者閱讀之后,能對(duì)項(xiàng)目有一個(gè)初步了解,更好的參與進(jìn)入的開發(fā)中。深度探索數(shù)據(jù)庫(kù)并發(fā)控制技術(shù)并發(fā)控制技術(shù)是數(shù)據(jù)庫(kù)事務(wù)處理的核心技術(shù)。 存儲(chǔ)過(guò)程高級(jí)篇 講解了一些存儲(chǔ)過(guò)程的高級(jí)特性,包括 cursor、schema、控制語(yǔ)句、事務(wù)等。 數(shù)據(jù)庫(kù)索引與事務(wù)管理 本篇文章為對(duì)數(shù)據(jù)庫(kù)知識(shí)的查缺補(bǔ)漏,從索引,事務(wù)管理,...

    csRyan 評(píng)論0 收藏0
  • 我的阿里路+Java面經(jīng)考點(diǎn)

    摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄业哪繕?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來(lái)的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開始了螞蟻金...

    姘擱『 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<