澤田 雅彦
@PostgreSQLアンカンファレンス
「LOG: process 12345 still waiting for ShareLock on
transaction 710 after 1000.269 ms」
のログについて
2
• 行ロック取得時(SELECT … FOR UPDATEなど)に、既に行ロックを取得しているトランザクションの完了(=
行ロックの開放)を待つときに出るログ
• トランザクションIDへのロックとは?
• それがなぜ行ロックに関係しているのか?
• 一方、LOG: process 58992 still waiting for AccessExclusiveLock on tuple (0,1) of relation 16384 of database
13021 after 1000.256 ms というログも出る
• FOR UPDATEのケースのみ解説します
LOG: process 61648 still waiting for ShareLock on transaction 710 after 1000.269 ms
DETAIL: Process holding the lock: 59735. Wait queue: 61648.
CONTEXT: while locking tuple (0,1) in relation "test"
3
ロックマネージャ(lmgr)
• ロックを管理する内部コンポーネント(すべてのプロセスで共有している)
• リレーション, タプル, ページ, トランザクションIDなど様々なものに対してロックが取得できる
• pg_locksビューで中身が見れる
• デッドロック検知機能がついている(deadlock_timeout)
• ロック待ちが発生するとログを出す(log_lock_waits)
• ロックは、スピンロック、軽量ロック、SIロックなど他にも色々ある
4
ロックレベル
5
トランザクションIDへのロック
• トランザクションID=各トランザクションが持つ一意の非負整数値
• トランザクションIDが払い出されたら、各トランザクションは自分のトランザクション
IDに対して排他ロックを取得する
• 自分のトランザクションIDに対する排他ロックはトランザクション完了時に開放される
6
トランザクションIDへのロック待ちとは?
LOG: process 61648 still waiting for ShareLock on transaction 710 after 1000.269 ms
• あるトランザクションIDへの共有ロックが取得できた=そのトランザクションが完了し
た
• 行ロックはこれを利用している
• つまりこのログは「あるトランザクション(xid=710)が先に行ロックを取得していて、プ
ロセス(pid=61648)はそのトランザクションが行ロックを開放するのを待っている」と理
解できる
7
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
Lmgr
Tuple
8
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
9
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
10
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
11
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
100
XID=100
XID=200
XID=100

EXL (BE-1)
XID=200

EXL (BE-2)
Lmgr
Tuple
12
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
100
XID=100
XID=200
XID=100

EXL (BE-1)
XID=200

EXL (BE-2)
Lmgr
Tuple
13
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く
BE-1
BE-2
100
XID=100
XID=200
XID=100

EXL (BE-1)
XID=200

EXL (BE-2)
Lmgr
Tuple
SHL (BE-2)
14
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く BE-2
100
XID=200
XID=200

EXL (BE-2)
Lmgr
Tuple
XID=100

SHL (BE-2)
15
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く BE-2
100
XID=200
XID=200

EXL (BE-2)
Lmgr
Tuple
16
ざっくりとした流れ
1. 自分のトランザクションIDに排他ロックを
取得
2. タプルのXMAXを確認して行ロックを取得
しているトランザクションを確認
3. 行ロックを取得しているトランザクション
の完了を待つ(=XIDへの共有ロックの取得)
4. 自分のXIDをXMAXに書く BE-2
200
XID=200
XID=200

EXL (BE-2)
Lmgr
Tuple
17
実はこれだけではうまく動かない
• 後から待ち始めたトランザクションが先に行ロックを取得できてしまう
18
行に対するロックをlmgr上で取得する
1. 自分のトランザクションIDに排他ロックを取得
2. 対象となる行に対してAccessExclusiveLockを取得
3. タプルのXMAXを確認して行ロックを取得しているトランザクションを確認
4. 行ロックを取得しているトランザクションの完了を待つ(=XIDへの共有ロックの取得)
5. 自分のXIDをXMAXに書く
6. 2で取得したAccessExclusiveLockを開放
19
BE-1
BE-2
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
20
BE-1
BE-2
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
21
BE-1
BE-2
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
tuple=(0,1)

AEL (BE-1)
22
BE-1
BE-2
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
tuple=(0,1)

AEL (BE-1)
23
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
tuple=(0,1)

AEL (BE-1)
24
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
25
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
26
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
tuple=(0,1)

AEL (BE-2)
27
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
tuple=(0,1)

AEL (BE-2)
SHL (BE-2)
28
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
tuple=(0,1)

AEL (BE-2)
SHL (BE-2)
LOG: process 61648 still
waiting for ShareLock on
transaction 710 after
1000.269 ms
29
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
tuple=(0,1)

AEL (BE-2)
SHL (BE-2)
BE-3
XID=300
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=300

EXL (BE-3)
30
BE-1
BE-2
100
XID=100
XID=100

EXL (BE-1)
Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200
XID=200

EXL (BE-2)
SHL (BE-2)
BE-3
XID=300
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
AEL (BE-3)
tuple=(0,1)

AEL (BE-2)
XID=300

EXL (BE-3)
31
BE-1
BE-2
100
XID=100 Lmgr
Tuple
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=200 BE-3
XID=300
1. Acquire the XID lock in EXL

2. Acquire the tuple lock in AEL

3. Check the blocker

4. Wait for the blocker to finish

5. Write own XID to XMAX field

6. Release the tuple lock
XID=100

EXL (BE-1)
XID=200

EXL (BE-2)
SHL (BE-2) AEL (BE-3)
tuple=(0,1)

AEL (BE-2)
XID=300

EXL (BE-3)
LOG: process 58992 still
waiting for
AccessExclusiveLock on
tuple (0,1) of relation
32
まとめ
• トランザクションは自分のトランザクションIDに対して排他ロックを取得する
• トランザクションIDに対する共有ロックの要求=そのトランザクションの完了待ち
• 最初に行ロックを待つトランザクションはトランザクションIDへの共有ロック待ちでログを出す
• それ以降に行ロックを待つトランザクションはタプルへの排他ロック待ちでログを出す
• タプルに対して(lmgr上で)AELを取得する事で待ち順を制御する
• 自分のブログでも以前にまとめています

トランザクションIDへのロックと行ロック: https://masahikosawada.github.io/2018/09/04/Row-locking-and-locking-on-
transactionid/

行ロックと「LOG: process 12345 still waiting for ShareLock on transaction 710 after 1000.269 ms」のログについて