txn-serializability-validator
The implementation is a complete conflict-serializability checker for concurrent database transaction schedules. It uses the standard serialization graph (precedence graph) approach:
Algorithm:
1. Graph construction — Process the operation stream left-to-right. For each operation, track lastRead and lastWrite per data item. When a transaction T₂ reads an item last written by T₁, add edge T₁ → T₂ (WR conflict). When T₂ writes an item last read or written by T₁, add edges T₁ → T₂ (RW and WW conflicts). Self-loops (same transaction) are ignored.
Key implementation:
// serializability.go — core logic
func CheckSchedule(ops []Operation) (bool, []int) {
// Build precedence graph from RW, WR, WW conflicts
for _, op := range ops {
switch op.Type {
case "R":
if w, ok := lastWrite[op.Item]; ok { addEdge(w, op.TxnID) }
lastRead[op.Item] = op.TxnID
case "W":
if r, ok := lastRead[op.Item]; ok { addEdge(r, op.TxnID) }
if w, ok := lastWrite[op.Item]; ok { addEdge(w, op.TxnID) }
lastWrite[op.Item] = op.TxnID
}
}
// Detect cycle via DFS
cycle := findCycle(graph, vertices)
return cycle == nil, cycle
}
All **25 tests pass** with **100% statement coverage**. Edge cases verified:
| Test | What it validates |
|---|---|
| `TestEmptySchedule` | Empty input → serializable |
| `TestSingleTransaction` | One transaction, no conflicts |
| `TestSelfLoopIgnored` | Same-txn R/W doesn't create self-edge |
| `TestSerializable{RW,WR,WW}Conflict` | Single edge directions |
| `TestSimpleCycleWRandRW` | Cycle from WR+RW on different items |
| `TestClassicNonSerializable` | Classic WW-WW cycle |
| `TestThreeTransactionDiamond` | Cycle detected in diamond pattern |
| `TestLongChainNoCycle` | Chain T₁→T₂→T₃ → serializable |
| `TestLongChainWithCycle` | Chain wraps around → cycle |
| `TestBlindWriteCycle` | Two WW conflicts forming a cycle |
| `TestCycleViaRWThenWR` | RW then WR on different items → cycle |
| `TestMultipleCycleFirstOne` | Two disjoint cycles, reports first |
| `TestLargeCycle` | 10-transaction cycle detected |
| `TestInvalidOperationType` | Bad `Type` field → error + single-txn cycle |
| `TestEmptyItem` | Empty `Item` field → error |
**Run output:**
```
$ go test -v -cover
=== RUN TestEmptySchedule --- PASS
...
=== RUN TestLargeCycle --- PASS
PASS
coverage: 100.0% of statements
```
---{"model": "claude-sonnet-4-20250514", "problem_class": "txn-serializability-validator", "result": "passed", "tests": 25}