なぜU-ロックはデッドロックを回避するのか
http://www.ccs.neu.edu/home/salzberg/transproc/jan20-99.psをPDF化
U-Locks
The most frequent reason for deadlocks
is conversion from S-locks to X-locks.
Suppose T1 has an S-lock on A and T2 has an S-lock on A
and T1 requests an Xlock on A and T2 requests an X-lock on A.
You get a deadlock. U-locks solve this problem.
U-locks would be used in update statements where the system must read
each record first to see if it satisfies a "where" clause.
Would U-locks be used in a transaction where a record is read
in an SQL Select statement first,
and then later updated in an Update Statement?
最もよく起きるデッドロックの原因は
S-ロックからX-ロックへのコンバージョンである。
T1がS-ロックをAに対してかけて、T2がS-ロックをAにかける
T1がX-ロックをAに対して要求し、T2もX-ロックをAに対して要求すると
デッドロックになる。U-ロックはこの問題を解決する。
U-ロックはupdate文で
システムが「where」句の条件をみたすレコードを
まず一件づつ読まなければならないときに使われる。
U-ロックは、最初にSQLのselect文でレコードを一件ずつ読んで
あとでupdate文で更新するトランザクションで使えるだろうか?
U-Locks
Salzberg's U-locks:
Clearing up the discussion on U locks.
Do not pay attention to what is in the text on U locks.
It does not make sense.
Here is the story: A U-lock is exactly the same as an S-lock
in its compatibility.
The only new information to remember is that
two U-locks are not compatible with each other.
U is compatible with S and IS.
When a U lock wants to convert to an X-lock,
it must obtain the necessary new higher granularity locks first.
And replace page 416 with the following:
SalzbergのU-ロック
U-ロックの議論を明確にするために、
U-ロックで何が行われるかに注目しないでほしい。
無意味なのだ。
こんな話:
U-ロックはS-ロックと互換性は全く同じである。
覚えておかなければならない新しい情報は
U-ロック自身はお互い互換性がないことである。
Partial Order on Locks
ロックの部分的な順序
o IS < S (or U)
o IS < IX
o IX < SIX
o S (or U) < SIX
o SIX < X
If A < B then any lock L which conflicts with A conflicts with B.
A < Bのとき、どんなロックもAと競合するものはBとも競合する。
Compatability Matrix for locks
Table 21. Lock Type Compatibility
State Being Requested\State of Held Resource
none IN IS NS S IX SIX U X Z NW W
none yes yes yes yes yes yes yes yes yes yes yes yes
IN yes yes yes yes yes yes yes yes yes no yes yes
IS yes yes yes yes yes yes yes yes no no no no
NS yes yes yes yes yes no no yes no no yes no
S yes yes yes yes yes no no yes no no no no
IX yes yes yes no no yes no no no no no no
SIX yes yes yes no no no no no no no no no
U yes yes yes yes yes no no no no no no no
X yes yes no no no no no no no no no no
Z yes no no no no no no no no no no no
NW yes yes no yes no no no no no no no yes
W yes yes no no no no no no no no yes no
Rules for requesting locks:
o Obtain an IS lock or stronger on all ancestors
before obtaining an S or IS lock on descendents
in the object hierarchy.
Reason: IS prevents X.
o Obtain a IX lock or stronger on all ancestors
before obtaining an X, IX or SIX or U lock on descendents
in the object hierarchy. Reason: IX prevents S (or U).
(This will prevent a deadlock if a lower granularity
and higher granularity U are both requested.)
S and X locks create implicit locks on objects lower in the object hierarchy.
If a file is S-locked, it is the same as if every record in the file were S-locked.
If a file is X-locked, it is the same as if every record were X-locked.
ロック要求のルール:
o オブジェクト階層のなかで、S-ロックまたはIS-ロックをすべての子孫に対して獲得する前に
IS-ロックかそれ以上に強いロックをすべての先祖に対して獲得する。
結果:ISはXを防ぐ
o オブジェクト階層のなかで、X、IX、SIX、U-ロックをすべての子孫に対して獲得する前に
IX-ロックかそれ以上に強いロックをすべての先祖に対して獲得する。
結果:IXはS(またはU)を防ぐ
(これでデッドロックを防ぐことができる。下位の部品と上位の部品が両方U-ロックを要求する。)
Lock Conversion
Within any LUW a process can only have one lock on a data object.Locks are hierarchical!
Conversion occurs when lower lock is held and a higher lock is needed.
If I hold an S lock on a row and I request a U lock The S lock is converted to U
If I hold an U lock on a row and I request a X lock The U lock is converted to X
DAG locks
A little on DAG locks. What if there are two indexes?
(This part uses key-range locks also.)
Example: T1 wants to update E and Xlocks [E G) as before.
T2 wants to read the record with socsecno = 333-33-3444.
But this record has alphakey = E.
If T2 does not also locking the alphakey,
or T1 does not also lock the socsecno,
there is a problem.
DAG locks continued
Answer: To update (or insert or delete),
X-lock all paths through indexes and to read,
set an S lock on one of the paths.
Problem: What about scanning the table without using an index?
(ok if T1 IX-locks the table and the scanner tries to get an
S-lock on the table.)
Another problem: suppose there are ten indexes
and there are 100 records with alphakey = E.
Answer: for each record updated, inserted or deleted,
all indexes must be key-range locked.
Instead of DAG locks
you can lock a record ID (RID or primary key) when it is read or updated,
even if you look it up by a secondary key. This will cause the correct conflicts. This is probably what systems do when they lock records. You still need the table lock or the key-range locks to prevent phantoms.
Locking Heuristics (sec 7.9, text)
o lock conversion
T1 has an S-lock or a U-lock
(compatible with S but not with X) and wants to convert to an Xlock.
T1 keeps the S-lock and requests the X-lock.
(We will see T1 goes to front of lock-wait queue for a lock conversion request)
o lock escalation
When a transaction has requested hundreds of record-granularity locks
on the same table, most systems will escalate the lock to a table-level lock,
dropping all the record-level locks.
o lock de-escalation
Some systems begin by making all locks table-granularity locks.
Then if there is a conflicting request, the lock is de-escalated
to recordlevel locks.
Transactions must maintain lists of the locks they would have requested
if record-level locks were used.
Nested Transaction Locks (sec 7.10)
Studying how nested transaction locks work explains
what nested transactions do. The semantics of nesting
can be derived from the mechanics of locking.
Sequential nested transactions are implemented in many systems,
such as DB2 and Sybase. Sybase has nested pairs of begin
and commit transaction statements. Only the outermost commit commits
the transaction. The inner pairs just keep track of the nesting level.
This nesting has no effect on locks.
If you have savepoints and rollback to a savepoint, the locks acquired after the savepoint are released (after the updates made since the savepoint are UNDONE).
Parallel Nesting
Parallel nested transactions allow any child to inherit a lock
from a parent (but not from a sibling). If a child subtransaction rolls back,
the inherited locks are returned to the parent and the acquired
locks are dropped. If a child commits, both inherited and acquired locks
go to the parent. If a sibling wants a lock another sibling has,
it has to wait.
Most systems do not support parallel nesting.
Deadlocks
The order transactions request locks cannot be predicted,
so deadlocks are always possible. Most systems use timeout
to resolve possible deadlocks. (If you have to wait a long time,
you are aborted.)
An alternative is to construct a waits-for graph. Transactions
which are waiting are nodes and there is an edge from T1 to T2
if T1 is waiting for T2. If there is a cycle in the graph,
there is a deadlock.
The transaction with the shortest number of log records might
be chosen to be aborted.
Deadlock is rare.
Only timeout is used for distributed deadlock.
The Convoy Phenomenon
Suppose T1 is running in a high-priority process and T2 has a low priority.
When doing process switches, T1 should be chosen more often than T2.
But suppose T2 acquires a lock on object X. T1 will have to wait for X.
Suppose T3 and T4 are also high priority and wait for X.
When T2 finally gets some time, (because higher priority processes are
no longer ready to run because they are waiting) T2 may run,
release the lock and get swapped out and then T1 runs, releases the lock
and goes to the end of the queue. T1, T3, T4 cycle forever.
(The lock in the text example is the endof-log lock,
which must be acquired for each update.) Solution: don't use a queue
for hot spots lock waiting, or spin rather than wait, or don't allow lock
holders to be pre-empted.
Mixed Multiversion Concurrency
Mixed multiversion concurrency: Readonly transactions read the most recent
version valid before their begin time. Read/Write transactions keep locks.
and put committime timestamps on the records they update (or the TID and
system keeps table correlating TID and commit time).
DEC's Rdb used this. Most systems do not.
A new transaction copies a TID vector: TIDs increase monotonically,
so all you need is the TID of the earliest non-committed transaction T1
(All TIDs less than T1s are from committed transactions) and the TIDs of
any transactions which have already committed and are greater than T1's TID.
Snapshot Isolation (from Berenson et al.)
o Readers can read data from the most
recent version committed before the begin time (start timestamp)
o Updating transactions: When T1 is ready to commit, if gets a commit
timestamp. Success if no other transaction T2 with commit timestamp in T1's
(start, commit) interval wrote data that T1 also wrote (first committer)
Otherwise T1 is aborted.
No locks. But also it does not guarantee isolation.
Examples for SI
T1 moves $40 from x to y; T2 reads an earlier version
H1SI: r1[x0=50] w1[x1=10]
r2[x0=50] r2 [y0=50] c2
r1[y0=50] w1[y1=90] c1
Here, T2<<
2003/08/28
ugya@lycos.com