Loading learning content...
In the previous page, we introduced conflict equivalence as the practical choice for schedule equivalence. Now we dive deep into this concept—understanding not just what it is, but why it works and how to apply it rigorously.
Conflict equivalence is the heart of practical serializability theory. It provides:
This page exhaustively explores conflict operations, the conflict equivalence rules, systematic conflict identification, and the theoretical properties that make this approach so powerful.
Understanding conflict equivalence deeply prepares you to construct precedence graphs (next page) and to understand how real database systems ensure transactional correctness.
By the end of this page, you will master the formal definition of conflicting operations, understand why each conflict type matters, systematically identify all conflicts in any schedule, and apply the conflict swap theorem to transform schedules while preserving equivalence.
Two operations from a set of concurrent transactions are said to conflict if the outcome of executing them depends on their order. Formally:
Operations Oᵢ and Oⱼ (from transactions Tᵢ and Tⱼ respectively, where i ≠ j) conflict if and only if ALL of the following conditions hold:
Conflict(Oᵢ, Oⱼ) ⟺ (Tᵢ ≠ Tⱼ) ∧ (item(Oᵢ) = item(Oⱼ)) ∧ (isWrite(Oᵢ) ∨ isWrite(Oⱼ))
Condition 1 (Different Transactions): Operations within the same transaction are ordered by the transaction's program logic. Only operations from different transactions can be reordered by the scheduler.
Condition 2 (Same Data Item): Operations on different data items are completely independent. r₁(A) and w₂(B) can be executed in either order with identical results.
Condition 3 (At Least One Write): Two read operations on the same item don't conflict because both merely observe the value—neither changes it. The order of reads doesn't affect what either sees.
Non-conflicting operations are truly independent: swapping their order in a schedule produces exactly the same result. This is why conflict equivalence works—we can reorder non-conflicting operations freely, and the only orderings that matter are between conflicting operations.
For two operations from different transactions on the same data item, the conflict matrix is:
| Read | Write | |
|---|---|---|
| Read | No Conflict (RR) | Conflict (RW) |
| Write | Conflict (WR) | Conflict (WW) |
Each conflict type has distinct implications for correctness and represents a different kind of dependency between transactions. Understanding these deeply is essential for analyzing concurrent behavior.
Pattern: rᵢ(X) ... wⱼ(X) or wⱼ(X) ... rᵢ(X)
A read-write conflict exists when one transaction reads a data item that another transaction writes.
Implications:
Example:
Initial: Balance = 1000
T₁: r₁(Balance) → sees 1000 (decides to withdraw 800)
T₂: w₂(Balance) = 500 (another withdrawal already processed)
If r₁ before w₂: T₁ thinks Balance is 1000 (incorrect assumption)
If w₂ before r₁: T₁ sees Balance is 500 (correct current state)
Pattern: wᵢ(X) ... rⱼ(X) or rⱼ(X) ... wᵢ(X)
Note: WR and RW conflicts are logically the same—just named from different perspectives.
A write-read conflict determines whether a read sees the written value.
Implications:
This is the conflict behind 'dirty reads' and 'non-repeatable reads':
Pattern: wᵢ(X) ... wⱼ(X)
A write-write conflict exists when two transactions both write to the same data item.
Implications:
This is the conflict behind 'lost updates':
Initial: Counter = 0
T₁: w₁(Counter) = 1
T₂: w₂(Counter) = 2
If w₁ then w₂: Final Counter = 2 (T₁'s update "lost")
If w₂ then w₁: Final Counter = 1 (T₂'s update "lost")
Both orderings are valid in isolation—the problem arises when neither transaction realizes the other exists, leading to semantically incorrect behavior (like both incrementing from the same base value).
| Conflict Type | Notation | Dependency Created | Potential Problem |
|---|---|---|---|
| Read-Write | rᵢ(X) ↔ wⱼ(X) | Read dependency | Non-repeatable read |
| Write-Read | wᵢ(X) ↔ rⱼ(X) | Write dependency | Dirty read |
| Write-Write | wᵢ(X) ↔ wⱼ(X) | Output dependency | Lost update |
Each conflict represents an ordering that MUST be maintained for the schedule to be equivalent to a particular serial order. If rᵢ(X) appears before wⱼ(X) in a schedule, then in any equivalent serial schedule, Tᵢ must execute before Tⱼ (at least with respect to their access to X).
To analyze any schedule, we need a systematic approach to find all conflicts. Here's a rigorous methodology:
Input: Schedule S with transactions T₁, T₂, ..., Tₙ
Output: Set of all conflicting pairs with their types and order
1. Create empty conflict set C
2. For each unique data item X accessed in S:
a. Collect all operations on X: Ops_X = {o | o accesses X}
b. For each pair (oᵢ, oⱼ) where oᵢ ∈ Tᵢ, oⱼ ∈ Tⱼ, and i < j:
- If both are reads: skip (no conflict)
- Otherwise:
* Determine conflict type (RW, WR, or WW)
* Determine order in S (which comes first)
* Add (oᵢ, oⱼ, type, order) to C
3. Return C
It helps to organize the analysis by data item:
Data Item: A
Operations: r₁(A) at position 1, w₂(A) at position 3, r₃(A) at position 5
Pairs to check:
- r₁(A), w₂(A): RW conflict, T₁ before T₂
- r₁(A), r₃(A): No conflict (both reads)
- w₂(A), r₃(A): WR conflict, T₂ before T₃
Data Item: B
Operations: w₁(B) at position 2, w₃(B) at position 4
Pairs to check:
- w₁(B), w₃(B): WW conflict, T₁ before T₃
Schedule S: r₁(A) w₂(A) r₂(B) w₁(B) r₃(A) w₃(B) w₂(B)
Positions:
1: r₁(A)
2: w₂(A)
3: r₂(B)
4: w₁(B)
5: r₃(A)
6: w₃(B)
7: w₂(B)Data Item A: r₁(A), w₂(A), r₃(A)
| Pair | Type | Order in S | Transaction Order |
|------|------|------------|-------------------|
| r₁(A), w₂(A) | RW | pos 1 < pos 2 | T₁ < T₂ |
| r₁(A), r₃(A) | RR | - | No conflict |
| w₂(A), r₃(A) | WR | pos 2 < pos 5 | T₂ < T₃ |
Data Item B: r₂(B), w₁(B), w₃(B), w₂(B)
| Pair | Type | Order in S | Transaction Order |
|------|------|------------|-------------------|
| r₂(B), w₁(B) | RW | pos 3 < pos 4 | T₂ < T₁ |
| r₂(B), w₃(B) | RW | pos 3 < pos 6 | T₂ < T₃ |
| r₂(B), w₂(B) | Same transaction | - | No conflict |
| w₁(B), w₃(B) | WW | pos 4 < pos 6 | T₁ < T₃ |
| w₁(B), w₂(B) | WW | pos 4 < pos 7 | T₁ < T₂ |
| w₃(B), w₂(B) | WW | pos 6 < pos 7 | T₃ < T₂ |
Summary of Conflicts:
- T₁ < T₂: r₁(A) before w₂(A), w₁(B) before w₂(B)
- T₂ < T₁: r₂(B) before w₁(B)
- T₂ < T₃: w₂(A) before r₃(A), r₂(B) before w₃(B)
- T₁ < T₃: w₁(B) before w₃(B)
- T₃ < T₂: w₃(B) before w₂(B)Notice the contradiction: T₁ < T₂ and T₂ < T₁, also T₂ < T₃ and T₃ < T₂. These circular dependencies indicate the schedule may not be conflict serializable. We'll verify this with a precedence graph in the next page.
A powerful way to understand conflict equivalence is through the swap theorem, which provides an operational definition of equivalence.
Theorem: Two schedules S₁ and S₂ are conflict equivalent if and only if S₁ can be transformed into S₂ by a sequence of swaps of adjacent non-conflicting operations.
S₁ ≡c S₂ ⟺ S₁ can be transformed to S₂ by swapping
adjacent non-conflicting operations
Non-conflicting operations are order-independent. If operations Oᵢ and Oⱼ don't conflict, then:
In any of these cases, executing Oᵢ before Oⱼ produces exactly the same result as executing Oⱼ before Oᵢ. The operations are truly independent.
Conflicting operations are order-dependent. The result changes based on which executes first. These operations cannot be swapped.
Original: r₁(A) r₂(B) w₁(A) w₂(B)
Can we reach: r₂(B) r₁(A) w₁(A) w₂(B)?
Step 1: Check if r₁(A) and r₂(B) conflict
- Different items (A vs B) → No conflict → Can swap!
After swap: r₂(B) r₁(A) w₁(A) w₂(B) ✓
These schedules are conflict equivalent.
| Adjacent Pair | Same Item? | At Least One Write? | Can Swap? |
|---|---|---|---|
| rᵢ(X), rⱼ(X) | Yes | No | Yes |
| rᵢ(X), wⱼ(X) | Yes | Yes | No |
| wᵢ(X), rⱼ(X) | Yes | Yes | No |
| wᵢ(X), wⱼ(X) | Yes | Yes | No |
| Any(X), Any(Y) | No | - | Yes |
| Oᵢ, Oᵢ | Same transaction | - | No (order fixed) |
S₁: r₁(A) r₂(B) w₁(A) r₂(A) w₂(A) w₂(B)
Serial (T₁→T₂): r₁(A) w₁(A) r₂(B) r₂(A) w₂(A) w₂(B)Step 1: S₁ = r₁(A) r₂(B) w₁(A) r₂(A) w₂(A) w₂(B)
Need to move r₂(B) after w₁(A)
Check: r₂(B) and w₁(A) conflict?
- Different items (B vs A) → No conflict → Swap!
Step 2: S = r₁(A) w₁(A) r₂(B) r₂(A) w₂(A) w₂(B) ✓
This equals the serial schedule T₁→T₂!
Conclusion: S₁ is conflict equivalent to serial (T₁→T₂)
→ S₁ is conflict serializableOne swap was enough to transform S₁ into a serial schedule. The key is that r₂(B) and w₁(A) don't conflict because they access different data items.
The swap theorem shows that conflict-equivalent schedules are 'rearrangements' of each other where only the non-essential orderings differ. All essential orderings (between conflicting operations) are preserved. This is why conflict equivalence captures 'same behavior'—the operations that affect results maintain their relative order.
Now we connect conflict equivalence to serializability through a fundamental theorem.
Statement: A schedule S is conflict serializable if and only if S is conflict equivalent to some serial schedule.
Corollary: A schedule S is conflict serializable if and only if there exists an ordering of transactions such that for every conflict, the transaction with the earlier operation comes first in that ordering.
Conflicts create ordering constraints between transactions. If operations from Tᵢ and Tⱼ conflict, and Tᵢ's operation comes first in the schedule, then Tᵢ must come before Tⱼ in any equivalent serial schedule.
Schedule S has: oᵢ <S oⱼ (conflicting operations)
↓
Equivalent serial: Tᵢ before Tⱼ (transaction order)
If these constraints are consistent (no cycles), we can find a serial order. If they're inconsistent (cycles exist), no serial order satisfies all constraints.
To prove a schedule S is conflict serializable:
Method 1: Find an Equivalent Serial Schedule
Method 2: Precedence Graph (Preferred)
We'll cover precedence graphs in complete detail on the next page.
To prove a schedule is NOT conflict serializable:
Show a cycle of conflicts:
Or show that the precedence graph has a cycle.
S: r₁(A) r₂(B) w₂(A) w₁(B)
Operations on A: r₁(A), w₂(A)
Operations on B: r₂(B), w₁(B)Conflict Analysis:
Data item A:
- r₁(A) at pos 1, w₂(A) at pos 3
- RW conflict: r₁(A) < w₂(A)
- Implies: T₁ must come before T₂
Data item B:
- r₂(B) at pos 2, w₁(B) at pos 4
- RW conflict: r₂(B) < w₁(B)
- Implies: T₂ must come before T₁
Contradiction!
- From A: T₁ < T₂
- From B: T₂ < T₁
No serial order can satisfy both T₁ < T₂ AND T₂ < T₁.
Conclusion: S is NOT conflict serializable.The two conflicts create contradictory ordering requirements. This is the classic 'cyclic dependency' that characterizes non-serializable schedules. The precedence graph would have edges T₁→T₂ and T₂→T₁, forming a cycle.
Any cycle in the conflict ordering requirements guarantees non-serializability. It's impossible to arrange transactions in a line where A comes before B, B comes before C, and C comes before A simultaneously. This observation is the foundation of the precedence graph test.
Conflict serializability has several important theoretical properties that make it suitable as the practical standard.
Every conflict-serializable schedule is view-serializable.
Proof sketch: If two schedules are conflict equivalent, they must be view equivalent. Conflict equivalence preserves read-from relationships because all read-write orderings are identical.
Conflict Serializable ⊂ View Serializable
The converse is NOT true—some view-serializable schedules are not conflict-serializable (involving blind writes).
The set of conflict-serializable schedules is closed under equivalence.
If S₁ is conflict serializable and S₂ ≡c S₁, then S₂ is also conflict serializable.
Proof: S₁ ≡c Ss (some serial). S₂ ≡c S₁. By transitivity, S₂ ≡c Ss. Therefore S₂ is conflict serializable.
If S is conflict serializable, any prefix of S (with completed transactions) is also conflict serializable.
This is crucial for concurrency control: we can make scheduling decisions incrementally, knowing that what we've accepted so far remains serializable.
Conflict serializability is composable under certain conditions.
If S₁ over {T₁, T₂} is serializable with order T₁→T₂, and S₂ over {T₂, T₃} is serializable with order T₂→T₃, then a combined schedule respecting both is serializable with order T₁→T₂→T₃.
Testing conflict serializability is in P (polynomial time).
This is in stark contrast to view serializability testing, which is NP-complete.
| Property | Statement | Significance |
|---|---|---|
| Inclusion | CS ⊂ VS | Sound but not complete for view correctness |
| Closure | Equivalent schedules share serializability | Consistency of classification |
| Prefix | Prefixes of serializable schedules are serializable | Enables incremental checking |
| Efficiency | Testing is O(n² × m²) | Practical for real systems |
| Sufficiency | Captures most useful schedules | Missing only blind-write cases |
Before diving into precedence graphs (next page), let's build intuition for why graph-based testing works.
Each conflict in a schedule imposes an ordering:
r₁(A) ... w₂(A) → T₁ must precede T₂ in any equivalent serial schedule
(because T₁ read A before T₂ changed it)
We can represent this as a directed edge: T₁ → T₂
Meaning: "T₁ comes before T₂"
Conflict 1: r₁(A) before w₂(A) → T₁ → T₂
Conflict 2: w₂(B) before r₃(B) → T₂ → T₃
Conflict 3: w₃(C) before w₁(C) → T₃ → T₁
These constraints form a graph:
T₁ → T₂ → T₃ → T₁ (cycle!)
A cycle T₁ → T₂ → T₃ → T₁ means:
But if T₁ < T₂ < T₃ < T₁, then T₁ < T₁. Contradiction!
No serial ordering can satisfy a cycle of constraints.
If there are no cycles, the constraints are consistent. We can find a topological sort of the graph—an ordering where every edge goes from earlier to later.
If graph is: T₁ → T₂, T₁ → T₃, T₂ → T₃
Topological sort: T₁, T₂, T₃
This is an equivalent serial schedule!
The precedence graph encodes ALL the ordering constraints implied by conflicts. Testing for cycles is equivalent to asking 'Can all these constraints be satisfied simultaneously?' If yes (acyclic), we can find a satisfying order. If no (cyclic), no such order exists.
S: r₂(A) w₁(A) r₁(B) w₂(B) w₃(A) r₃(B)
Transactions: T₁, T₂, T₃Conflicts identified:
1. r₂(A) at 1, w₁(A) at 2: T₂ → T₁
2. r₂(A) at 1, w₃(A) at 5: T₂ → T₃
3. w₁(A) at 2, w₃(A) at 5: T₁ → T₃
4. r₁(B) at 3, w₂(B) at 4: T₁ → T₂
5. r₁(B) at 3, r₃(B) at 6: No conflict (RR)
6. w₂(B) at 4, r₃(B) at 6: T₂ → T₃
Graph edges:
- T₂ → T₁ (conflict 1)
- T₂ → T₃ (conflicts 2, 6)
- T₁ → T₃ (conflict 3)
- T₁ → T₂ (conflict 4)
Cycle check:
T₁ → T₂ and T₂ → T₁ form a cycle!
Conclusion: Not conflict serializableThe cycle T₁ → T₂ → T₁ (or equivalently T₂ → T₁ → T₂) indicates contradictory constraints. T₁ must be before T₂ (conflict 4) but also T₂ must be before T₁ (conflict 1). No serial order satisfies both.
We've thoroughly explored conflict equivalence—the practical foundation of serializability testing. Let's consolidate the essential concepts:
What's Next:
We've built all the theory needed to understand the precedence graph—the practical tool for testing conflict serializability. The next page covers precedence graph construction, cycle detection, and extracting equivalent serial orders from acyclic graphs. This becomes the standard algorithm used in database theory and practice.
You now have a complete understanding of conflict equivalence: what conflicts are, how to identify them systematically, why the swap theorem works, and how cycles in conflict orderings indicate non-serializability. Next, we'll formalize this into the precedence graph algorithm for efficient serializability testing.