Timestamp ordering
Concurrency control without locks: every transaction gets a timestamp when it starts, every item remembers the largest timestamp of a reader and of a writer, and an operation that would break the timestamp order is rejected and its transaction restarted with a new timestamp; the read and write rules, the Thomas write rule and view serializability, why the protocol is conflict serializable and deadlock free but neither recoverable nor starvation free, strict timestamp ordering, the timestamp-based deadlock prevention schemes wait-die and wound-wait for locking, multiversion timestamp ordering in outline, and a comparison with two-phase locking over all interleavings of small transaction sets.
Why it exists
Locking decides the order of conflicting operations as the transactions run: whoever gets the lock first goes first, and a transaction that cannot get a lock waits, so deadlocks can arise. Timestamp ordering decides the order in advance. Each transaction is given a number when it starts; the protocol makes sure that every pair of conflicting operations is executed in the order of these numbers, as if the transactions had run one after another in order of their numbers. An operation that arrives too late is not made to wait: its transaction is rolled back and restarted with a new number. Nobody ever waits, so there are no deadlocks.
Prerequisites
You need conflicts, precedence graphs and conflict serializability (schedules and serializability). The comparison with locking uses two-phase locking, and the part on recoverability uses recoverable and strict schedules.
Precise definitions
Timestamp. Each transaction receives a unique timestamp when it starts, from a clock or a counter, increasing with time. A smaller timestamp means an older transaction.
Item timestamps. For every item the system keeps
- : the largest timestamp of any transaction that has successfully read ;
- : the largest timestamp of any transaction that has successfully written .
Both start at 0.
The rules (basic timestamp ordering) for an operation of on :
- reads . If , a younger transaction has already overwritten , so would read a value from its future: abort . Otherwise execute the read and set .
- writes . If , a younger transaction has already read and would have needed this value: abort . If , a younger transaction has already written : abort . Otherwise execute the write and set .
An aborted transaction is rolled back and restarted with a new, larger timestamp. The rule can be said in one sentence: an operation is rejected exactly when a younger transaction has already made a conflicting access to the item.
Thomas write rule. In the second write case (, but ) the write is ignored instead of aborting : the value would be overwritten at once by the younger writer and nobody has read it.
Strict timestamp ordering. A read or write that passes the test but would read or overwrite a value written by a transaction that has not committed is delayed until that transaction commits or aborts.
Deadlock prevention with timestamps (for locking). Two schemes use timestamps as priorities when a lock request conflicts with a lock held by another transaction:
- Wait-die (non-preemptive): if the requester is older than the holder, it waits; if it is younger, it dies (is rolled back).
- Wound-wait (preemptive): if the requester is older, it wounds the holder (the holder is rolled back and the requester takes the lock); if it is younger, it waits.
In both, a rolled-back transaction restarts with its original timestamp.
How it works
The rules on every pair of conflicting operations
The rules on the six conflicting pairs: start
Computed by a script, not typed| pair | first operation | second operation | basic protocol | Thomas write rule | reason (basic protocol) |
|---|---|---|---|---|---|
| r1(X) then w2(X) | |||||
| r2(X) then w1(X) | |||||
| w1(X) then r2(X) | |||||
| w2(X) then r1(X) | |||||
| w1(X) then w2(X) | |||||
| w2(X) then w1(X) |
Step 0
TS(T1) = 1 (older), TS(T2) = 2 (younger). Item X starts with R-TS = W-TS = 0. A row is a first operation by one transaction followed by a conflicting second operation by the other. The decision is about the second operation.
Two transactions: older, younger. A read and a read never conflict. When the older transaction acts first, everything is fine: the order of the operations agrees with the order of the timestamps. When the younger acts first and the older follows with a conflicting operation, the older one is rejected, because it arrives too late. The single exception in the last row is the Thomas write rule, which skips the late write instead of aborting.
A schedule run through the protocol
Basic timestamp ordering on a schedule of three transactions: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
|---|---|---|---|---|---|---|---|---|---|
| operation | |||||||||
| decision | |||||||||
| R-TS (A, B, C) | |||||||||
| W-TS (A, B, C) |
Step 0
Timestamps are given in the order in which the transactions start: TS(T1) = 1, TS(T2) = 2, TS(T3) = 3. All R-TS and W-TS start at 0. A step handles one operation of the schedule r1(A) r2(B) w2(C) w3(A) w1(B) r2(A) c3 c1 c2.
Read the table column by column: and grow only when an operation is accepted. is rejected because (younger) has read ; is rejected because (younger) has written . The aborted transactions' remaining operations disappear from the schedule; they will run again after the restart with new timestamps. The accepted operations , , and followed the timestamp order.
Why it is serializable and deadlock free
Every accepted pair of conflicting operations is in timestamp order, so every edge of the precedence graph goes from a smaller to a larger timestamp. A cycle would need an edge going back, so the graph is acyclic: the schedule is conflict serializable, equivalent to the serial schedule in timestamp order. The checks confirm the converse as well: a schedule passes without abort exactly when each conflicting pair is in timestamp order. No operation ever waits, so no deadlock can occur. The price is restarts: a transaction can be aborted again and again (starvation is possible), and the work done before the abort is lost.
Restarts get new timestamps
An abort, a restart with a new timestamp, and a wait: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
|---|---|---|---|---|---|---|---|---|---|
| transaction (timestamp) | |||||||||
| operation | |||||||||
| decision |
Step 0
T1 = r(A) w(B) and T2 = r(B) w(A), the transactions take turns (T1, T2, T1, T2, ...). They start with TS(T1) = 1 and TS(T2) = 2; a restarted transaction takes the next number of the counter. Strict timestamp ordering: an operation that passes the timestamp test but would touch a value written by an uncommitted transaction waits.
is aborted at step 3 because (younger) has read . It restarts with the timestamp 3, larger than all existing ones, which means it is now the youngest transaction. Its new read of passes the test but would read a value written by the uncommitted , so it waits (this run uses the strict variant, explained below); after commits it goes through. The final order of the committed work is then : the order of their final timestamps, 2 and 3.
The Thomas write rule
The Thomas write rule: skipping an obsolete write: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|
| operation | |||||||
| basic protocol | |||||||
| Thomas write rule | |||||||
| W-TS(A) with the Thomas rule |
Step 0
T1 reads A, then T2 and T1 write A in the wrong order, then T3 writes A. The precedence graph has the cycle T1 → T2 → T1, so the schedule is not conflict serializable, but it is view serializable (equivalent to the serial order T1 T2 T3: T1 reads the initial A and T3's write is the final one). TS(T1) = 1, TS(T2) = 2, TS(T3) = 3.
The schedule has the conflicts and , a cycle, so it is not conflict serializable. The basic protocol aborts at . With the Thomas rule, is skipped: has already written , nobody has read 's value, and 's later write will overwrite everything anyway. The outcome (the values read, the final database) equals that of the serial execution , so the schedule is view serializable. The check ran this on symbolic values for every schedule the rule accepts and found no difference from the serial execution in timestamp order. So the Thomas rule accepts more schedules than conflict serializability allows, but stays view serializable.
Not recoverable: the dirty read
Basic timestamp ordering allows a dirty read: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|
| operation | ||||||
| decision | ||||||
| R-TS (A, B) | ||||||
| W-TS (A, B) |
Step 0
T1 writes A and B; T2 reads A and B and commits. TS(T1) = 1, TS(T2) = 2. The schedule w1(A) r2(A) r2(B) c2 w1(B) c1 is attempted under the basic protocol, which says nothing about commits.
The basic protocol only looks at timestamps. reads the value of that wrote and has not committed, and commits. Then is aborted at (because has read ). has committed a result computed from a value that never officially existed: the schedule is not recoverable (a transaction committed before the one it read from). The usual repair is the strict variant:
Strict timestamp ordering delays the reader: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| transaction (timestamp) | ||||||||
| operation | ||||||||
| decision |
Step 0
The same two transactions under strict timestamp ordering, attempted in the order T1, T2, T2, T1, T1, T2, ... A read or write that passes the timestamp test but touches an uncommitted value waits until that value's writer commits (or aborts).
Now the reader waits. 's read of is delayed until commits; is not aborted because has not yet read . The resulting schedule is strict. A wait only ever points to an older transaction (a transaction waits for the writer of a value, and a writer that passed the test has a smaller timestamp), so even strict timestamp ordering has no deadlock.
Timestamps used against deadlocks in locking
When locks are used, a conflicting request makes the requester wait, and cycles of waiting are deadlocks. Wait-die and wound-wait use the timestamps to forbid such cycles:
Wait-die and wound-wait: who waits and who is rolled back: start
Computed by a script, not typed| situation | wait-die (non-preemptive) | wound-wait (preemptive) |
|---|---|---|
| requester is older than the holder | ||
| requester is younger than the holder |
Step 0
T1 has timestamp 1 (older), T2 has timestamp 2 (younger). One transaction holds an exclusive lock on X; the other asks for a conflicting lock. The cell says what the scheme decides. Rolled-back transactions keep their timestamps when they restart.
Both schemes make every wait go in one direction of age: in wait-die only an older transaction waits for a younger one; in wound-wait only a younger waits for an older. A cycle would need a wait in the other direction somewhere, so no deadlock is possible (the check confirmed that the waits-for graph never had a cycle, also when a lock passed to a new holder while others were waiting). The same two transactions without any prevention end in a deadlock:
Without prevention: a deadlock: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | then | |
|---|---|---|---|---|---|
| transaction (timestamp) | |||||
| request | |||||
| outcome | |||||
| waits-for edges | |||||
| locks held |
Step 0
T1 = w(A) w(B) and T2 = w(B) w(A) with exclusive locks held until commit, taking turns (T1, T2, T1, T2, ...). TS(T1) = 1 (older), TS(T2) = 2. No prevention: a transaction that cannot get a lock waits.
and with the two schemes:
Wait-die on the same two transactions: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
|---|---|---|---|---|---|---|---|---|---|---|
| transaction (timestamp) | ||||||||||
| request | ||||||||||
| outcome | ||||||||||
| waits-for edges | ||||||||||
| locks held |
Step 0
T1 = w(A) w(B) and T2 = w(B) w(A) with exclusive locks held until commit, taking turns (T1, T2, T1, T2, ...). TS(T1) = 1 (older), TS(T2) = 2. Wait-die: an older requester waits for a younger holder; a younger requester dies.
Wound-wait on the same two transactions: start
Computed by a script, not typed| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| transaction (timestamp) | ||||||||
| request | ||||||||
| outcome | ||||||||
| waits-for edges | ||||||||
| locks held |
Step 0
T1 = w(A) w(B) and T2 = w(B) w(A) with exclusive locks held until commit, taking turns (T1, T2, T1, T2, ...). TS(T1) = 1 (older), TS(T2) = 2. Wound-wait: an older requester wounds a younger holder; a younger requester waits.
In wait-die the younger dies at step 4 when it asks for held by older , and again at step 6 (it retries at once here; a real system delays the restart). In wound-wait the older wounds the younger holder at step 3. Because a restarted transaction keeps its original timestamp, the oldest transaction is never rolled back in either scheme, so every transaction eventually becomes the oldest and finishes: there is no starvation. (This is different from timestamp ordering, where a restart takes a new, larger timestamp.)
Timestamp ordering against two-phase locking
Timestamp ordering against two-phase locking over all interleavings: start
Computed by a script, not typed| transactions | interleavings | conflict serializable | accepted by timestamp ordering | producible by 2PL | both | timestamp ordering only | 2PL only |
|---|---|---|---|---|---|---|---|
| T1 = w(B) r(B), T2 = r(B) | |||||||
| T1 = w(B) w(C), T2 = r(C) | |||||||
| T1 = r(A) w(B), T2 = w(A) w(B), T3 = r(B) w(C) |
Step 0
For each set of transactions every interleaving of their operations is generated. A schedule is accepted by timestamp ordering if no operation is rejected when the transactions get timestamps in the order of their first operations. It can be produced by two-phase locking if shared and exclusive lock and unlock operations can be inserted so that the schedule is legal and every transaction is two-phase.
For small sets of transactions, every interleaving was generated. Both protocols produce only conflict serializable schedules, but neither produces everything the other does. The first row has a schedule accepted by timestamp ordering that locking cannot produce ( must keep its exclusive lock on until its last read of , so 's read cannot come in between). The second row has a schedule that locking produces and timestamp ordering rejects ( started first, so it is older, but read before wrote it: the serial order is then , against the timestamps). Locking puts the order in the order of lock points, timestamp ordering in the order of start times.
Multiversion timestamp ordering (quoted)
If every write creates a new version of the item, labelled with the writer's timestamp, a read never has to be rejected: it is given the version with the largest write timestamp not larger than the reader's timestamp. A write is rejected only if a younger transaction has already read the version the write would follow. This increases concurrency, at the cost of storing versions. It is described in the textbooks and is not computed here.
Worked examples
EX 1The rules on one item
Easy, . Item has and . The operations arrive in this order.
: , a younger transaction has read : is aborted. : : executed, becomes . : and : executed, becomes 20. : : would read a value from its future, abort.
EX 2Does the protocol accept the schedule?
MediumThe timestamps follow the order in which the transactions first appear. Check every pair of conflicting operations: the earlier must belong to the transaction with the smaller timestamp.
: before is fine (1 before 2) but before has the larger timestamp first: rejected at (it is not conflict serializable either). : the only conflict is before , in order: accepted. : is fine but is not: rejected at .
EX 3What the Thomas write rule changes
Mediumwith timestamps 1, 2, 3. The first three operations are accepted. At : , but . The basic protocol aborts . The Thomas rule skips the write and lets continue. is accepted in both versions.
EX 4Typical questions
GATE level(a) " and . holds a lock and asks for a conflicting one." Wait-die: is older, so it waits. Wound-wait: is older, so it wounds (rolled back). (b) " holds the lock and asks." Wait-die: is younger, so it dies. Wound-wait: waits. (c) "Is timestamp ordering free from deadlock?" Yes, nothing waits. "From starvation?" No: a transaction may be restarted again and again. (d) "Is every schedule produced by timestamp ordering recoverable?" No (the dirty read above). (e) "Which schedules does the Thomas write rule add?" View serializable schedules that are not conflict serializable. (f) "Is every conflict serializable schedule accepted by timestamp ordering?" No: it must also follow the order of the timestamps, for example is conflict serializable (serial order , ) but with older it is rejected at .
Cheat box
Cheat box
- Read: abort if . Write: abort if or . Else execute and update (max) or .
- Thomas write rule: if only holds (not ), skip the write.
- An operation is rejected when a younger transaction has already made a conflicting access.
- Conflict serializable in timestamp order; no deadlock; starvation possible; not recoverable (strict variant delays reads and writes of uncommitted values).
- Restart: new timestamp. Wait-die and wound-wait: restart with the old timestamp.
- Wait-die: older waits, younger dies. Wound-wait: older wounds, younger waits. Both deadlock free.
- Timestamp ordering and two-phase locking produce incomparable sets of schedules.
Traps and GATE patterns
Connections
Timestamp ordering and two-phase locking both guarantee serializability, by different means: ordering decided at the start against ordering decided by the lock points. Their difference in recoverability is a typical exam topic. The wait-die and wound-wait schemes prevent the circular wait of deadlock by breaking its symmetry with an age.
PYQs
3 previous year questions from your book. I re-solved each one myself (0 by running or simulating, 3 by reasoning only); the book's key is shown next to my answer. All PYQs
Consider the following two statements about database transaction schedules: I. Strict two-phase locking protocol generates conflict serializable schedules that are also recoverable. II. Timestamp-ordering concurrency control protocol with Thomas write rule can generate view serializable schedules that are not conflict serializable. Which of the above statements is/are TRUE?
- (a)Both I and II
- (b)Neither I nor II
- (c)II only
- (d)I only DATABASE MANAGEMENT SYSTEM
In a database system, unique timestamps are assigned to each transaction using Lamport 's logical clock. Let TS(T1) and TS(T2) be the timestamps of transactions T1 and T2 respectively. Besides, T1 holds a lock on the resource R and T2 has requested a conflicting lock on the same resource R. The following algorithm is used to prevent deadlocks in the database system assuming that a killed transaction is restarted with the same timestamp. if TS(T2) < TS(T1) then T1 is killed else T2 waits. Assume any transaction that is not killed terminates eventually. Which of the following is TURE about the database system that uses the above algorithm to prevent deadlocks?
- (a)The database system is both deadlock-free and starvation-free.
- (b)The database system is deadlock-free, but not starvation-free.
- (c)The database system is starvation-free, but not deadlock-free.
- (d)The database system is neither deadlock-free nor starvation-free.
Which of the following concurrency control protocols ensure both conflict serializability and freedom from deadlock? I. 2-phase locking II. Time-stamp ordering
- (a)I only
- (b)II only
- (c)Both I and II
- (d)Neither I nor II
Self-check
Question 1
, and for item : , . What happens if writes ? If reads ?
Show answerHide
The write is rejected (): is aborted. The read is accepted () and stays 9, the larger value.
Question 2
Is (with older) accepted by timestamp ordering? Is it conflict serializable?
Show answerHide
It is conflict serializable (serial order then ). Timestamp ordering rejects because , younger, has already read .
Question 3
In wound-wait, an older transaction asks for an item held by a younger one. What happens, and what if the roles are exchanged?
Show answerHide
The younger holder is wounded (rolled back) and the older takes the lock. If the younger asks for an item held by the older, the younger waits.
Revision card
One-screen revision
- Timestamp = start time; smaller means older. Keep and (largest reader and writer).
- Read rejected if . Write rejected if or ; Thomas: skip when only is larger.
- Conflict serializable in timestamp order, no deadlock, starvation possible, not recoverable.
- Wait-die: older waits, younger dies. Wound-wait: older wounds, younger waits. Restart with the old timestamp.
- Incomparable with two-phase locking.
References
- ·Silberschatz, Korth, Sudarshan, Database System Concepts (7th edition), Chapter 18 (Concurrency Control): timestamp-based protocols, deadlock prevention, multiversion schemes
- ·Elmasri, Navathe, Fundamentals of Database Systems (7th edition), Chapter 21 (Concurrency Control Techniques): timestamp ordering, strict timestamp ordering, multiversion
Verification
scripts/enum-checks/db_timestamp_check.py: (1) over all interleavings of many random sets of tiny transactions (10651 schedules) and for the entry-order timestamps and every permutation of timestamps, the basic protocol accepts a schedule without abort exactly when it is conflict equivalent to the serial schedule in timestamp order (tested with the conflict-equivalence of scripts/db_txn.py, not with R-TS and W-TS), and R-TS and W-TS equal the largest timestamps of the accepted reads and writes; (2) for the Thomas write rule, every accepted schedule gave, on symbolic values with the ignored writes left out, the same final database and the same values read by every transaction as the serial execution in timestamp order; 2530 schedules were accepted only thanks to the rule and 1875 of them are not conflict serializable; (3) strict timestamp ordering with restarts under random turn orders (1500 runs, 4162 waits, 2240 restarts) always finished, every wait pointed to an older transaction, the history was strict, conflict serializable in the order of the final timestamps and equal to the serial execution on symbolic values; (4) wait-die and wound-wait under random programs, timestamps and turn orders (2400 runs): always finished, the waits-for graph was acyclic at every step and waits pointed the permitted way, the oldest transaction was never rolled back, the history was strict and conflict serializable; without prevention 184 of 1200 runs ended in a deadlock and then the waits-for graph had a cycle; (5) the test whether a schedule can be produced by two-phase locking (every transaction picks a lock point) agreed with a backtracking search over all placements of lock, upgrade and unlock operations on 4009 schedules; an earlier version of the test, which acquired locks as late as possible, was WRONG (the search found schedules it rejected wrongly) and was replaced. CONVENTIONS: timestamps are given in the order in which the transactions first appear in the schedule, a smaller timestamp is an older transaction, R-TS and W-TS are never rolled back when a transaction aborts, a transaction aborted by the protocol restarts from its first operation with a new, larger timestamp, in wait-die and wound-wait a restarted transaction keeps its old timestamp and a waiting request is judged again when the lock passes to a new holder. NOT COMPUTED, quoted from the textbooks: the multiversion protocol. Chapter and section numbers are from memory and need verification. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and re-derived against the textbook definitions and the sample database. No defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)