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