Lock-Based Scheduler
This is a Scheduler that gives Conflict-Serializable Schedule
This scheduler is pessimistic:
- it assumes that something will go wrong, and it's going to prevent that
Notation:
- w(X) - write X
- r(X) - read X
- l(X) - lock X
- u(X) - unlock X
Rule:
- before a transaction Ti can read or write a database item X, it must obtain the lock on X
- if Ti requests a lock that is already taken by other transaction Tj, it's paused until Tj releases the lock
- so it's impossible for both Ti and Tj to have a lock on the same database element at the same time
Example
The following is a legal lock-based schedule:
T1 |
T2 |
|
l1(A),r1(A) |
|
|
w1(A) |
|
|
l1(B),u1(A) |
|
|
|
l1(A),r2(A) |
|
|
w2(A) |
|
l2(B) |
|
lock is denied, T2 pauses
|
r1(B),w1(B) |
|
|
r1(B),w1(B) |
|
|
u1(B) |
|
T1 releases B, T2 can proceed
|
|
l2(B),u2(A) |
|
|
r2(B),w2(B) |
|
|
u2(B) |
|
Another example:
S=
T1 |
T2
|
l1(A),r1(A),w1(A),u1(A), |
|
|
l2(A),r2(A),w2(A),u2(A),
|
|
l2(B),r2(B),w2(B),u2(B),
|
l1(B),r1(B),w1(B),u1(B) |
|
Is it conflict-serializable?
- We build a precedence graph:
- there is a cycle! → no conflict serializability
- so even if a lock-based schedule is legal, it doesn't mean it's conflict-serializable
Tho-Phase Locking
To get a conflict-serializable schedule:
- for each Ti, all lock requests li must precede unlock requests ui
In other words
- we can acquire as many locks as you want,
- but then can only unlock them without being able to acquire them again
- → cannot do li(X),ui(X),li(X),ui(X) within the same transaction Ti
→ all locks are released after the entire manipulation with a DB object is completed
- this way the schedule is guaranteed to be conflict-serializable
Theorem
A schedule S obtained by Tho-Phase Locking is conflict-serializable
Proof:
Suppose we have a schedule S in which a transaction doesn't lock after unlocking
- we want to show that we can transform S into a conflict-serializable one by conflict-free swapping
For a schedule with one transaction it's trivial
- assume several transactions
Suppose we have the following schedule:
- S=...,wB(X),...,uB(X),...,lA(X),...,uA(X),...,rA(X),...
- since B unlocks X there must be lB(X) that precedes uB(X)
- in this case all actions for element X are performed only by transaction B
- by conflict-free swapping can move all actions on X to the front of the schedule
- then remove them and repeat for the remaining elements
◻
In Practice
- Transaction manager sends read/write requests
- The scheduler itself inserts locks and unlocks - the transactions don't know anything about them
- Also the locks are usually released after commit
- so if a transaction T2 waits for a lock, it will usually wait until another transaction T1 that keeps the lock commits
Cons and Pros
- Locking is very effective when we have many transactions that both read and write
- When you have few transactions that write it's not efficient - many transactions will have to wait for locks
Other Approaches
There are no problems with two transactions that read at the same time (as long as none of them write)
- there are different kind of locks for that
- Shared Locks - for reading at the same time
- Exclusive Locks - if you also want to write
Also there are hierarchical locks
- locks not on a tuple, but on the whole block
Sources