TASK
Implementation
Three-Phase Commit (3PC) adds an extra phase to 2PC to reduce blocking scenarios. The third phase (PreCommit) ensures participants know a commit is imminent.
Protocol phases:
- CanCommit: Coordinator asks "Can you commit?" Participants acquire locks and write to WAL, then vote Yes/No
- PreCommit: If all voted Yes, coordinator sends
PreCommit. Participants acknowledge and enter "pre-committed" state - DoCommit: Coordinator sends
DoCommit. Participants apply changes and sendHaveCommitted
State transitions:
Participant states:
→ INITIAL → CAN_COMMIT? → PRE_COMMITTED → COMMITTED
↓ ↓
ABORTED ABORTEDExample 3PC execution:
Request: {"type": "txn_begin", "msg_id": 1, "participants": ["p1", "p2", "p3"], "operations": [{"transfer": 100, "from": "a", "to": "b"}]}
Response: {"type": "txn_begin_ok", "in_reply_to": 1, "txn_id": "txn42"}
// Phase 1: CanCommit
{"type": "can_commit", "msg_id": 2, "txn_id": "txn42"}
{"type": "can_commit_yes", "in_reply_to": 2, "txn_id": "txn42", "participant": "p1"}
{"type": "can_commit_yes", "in_reply_to": 2, "txn_id": "txn42", "participant": "p2"}
{"type": "can_commit_yes", "in_reply_to": 2, "txn_id": "txn42", "participant": "p3"}
// Phase 2: PreCommit
{"type": "pre_commit", "msg_id": 3, "txn_id": "txn42"}
{"type": "pre_commit_ack", "in_reply_to": 3, "txn_id": "txn42", "participant": "p1"}
{"type": "pre_commit_ack", "in_reply_to": 3, "txn_id": "txn42", "participant": "p2"}
{"type": "pre_commit_ack", "in_reply_to": 3, "txn_id": "txn42", "participant": "p3"}
// Phase 3: DoCommit
{"type": "do_commit", "msg_id": 4, "txn_id": "txn42"}
{"type": "have_committed", "in_reply_to": 4, "txn_id": "txn42", "participant": "p1"}
{"type": "have_committed", "in_reply_to": 4, "txn_id": "txn42", "participant": "p2"}
{"type": "have_committed", "in_reply_to": 4, "txn_id": "txn42", "participant": "p3"}Why 3PC helps:
If coordinator crashes after PreCommit, participants know:
- All participants voted Yes
- A commit is imminent
- They can safely commit without waiting for recovery
Sample Test Cases
Successful 3PC transactionTimeout: 5000ms
Input
{"src":"c0","dest":"coord","body":{"type":"init","msg_id":1,"participants":["p1","p2","p3"]}}
{"src":"c1","dest":"coord","body":{"type":"txn_begin","msg_id":2,"participants":["p1","p2"],"operations":[{"transfer":100,"from":"a","to":"b"}]}}
Expected Output
{"src": "coord", "dest": "c0", "body": {"type": "init_ok", "in_reply_to": 1, "msg_id": 0}}
Participant votes No in CanCommitTimeout: 5000ms
Input
{"src":"c0","dest":"coord","body":{"type":"init","msg_id":1,"participants":["p1","p2"]}}
{"src":"c1","dest":"coord","body":{"type":"txn_begin","msg_id":2,"participants":["p1","p2"],"operations":[{"transfer":999999,"from":"a","to":"b"}]}}
Expected Output
{"src": "coord", "dest": "c0", "body": {"type": "init_ok", "in_reply_to": 1, "msg_id": 0}}
Hints
Hint 1▾
Phase 1 (CanCommit): coordinator asks "Can you commit?" Participants vote Yes/No
Hint 2▾
Phase 2 (PreCommit): coordinator sends PreCommit if all voted Yes. Participants acknowledge
Hint 3▾
Phase 3 (DoCommit): coordinator sends DoCommit. Participants commit and acknowledge
Hint 4▾
The key: PreCommit lets participants know a commit is coming, enabling recovery
Hint 5▾
If coordinator crashes after PreCommit, participants can commit without waiting
OVERVIEW
Theoretical Hub
Concept overview coming soon
Key Concepts
three-phase commitCanCommitPreCommitDoCommitnon-blocking commitcoordinator recovery
main.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/env python3
import sys
import json
def main():
# Your implementation here
for line in sys.stdin:
msg = json.loads(line)
print(json.dumps(msg), flush=True)
if __name__ == "__main__":
main()