{
  "docVersion": 1,
  "id": "blog-2pc-0001",
  "name": "Two-phase commit — and the moment it blocks",
  "purpose": "A coordinator runs 2PC across three stores: prepare/vote, then commit. The coordinator crashes after collecting votes — participant C is in doubt, holding locks, unable to commit or abort.",
  "nodes": {
    "client": {
      "type": "user",
      "label": "Client",
      "x": 20,
      "y": 280,
      "runtime": "one atomic transaction"
    },
    "coord": {
      "type": "server",
      "label": "Coordinator",
      "x": 300,
      "y": 280,
      "color": "red",
      "style": "dashed",
      "runtime": "CRASHED after votes",
      "notes": "Writes every decision to its transaction log first. Its crash between collecting votes and broadcasting COMMIT is the famous failure: participants that voted YES can neither commit nor abort until it returns."
    },
    "pa": {
      "type": "database",
      "label": "Orders DB",
      "x": 680,
      "y": 60,
      "color": "green",
      "runtime": "COMMIT received"
    },
    "pb": {
      "type": "database",
      "label": "Inventory DB",
      "x": 680,
      "y": 280,
      "color": "green",
      "runtime": "COMMIT received"
    },
    "pc": {
      "type": "database",
      "label": "Payments DB",
      "x": 680,
      "y": 500,
      "color": "amber",
      "runtime": "IN DOUBT — locks held",
      "notes": "Voted YES, so it promised it CAN commit — it durably staged the write and holds locks. Until the coordinator recovers, it must keep that promise open: blocked."
    }
  },
  "edges": {
    "e0": {
      "from": "client",
      "to": "coord",
      "fromSide": "right",
      "toSide": "left",
      "label": "commit order + stock + charge"
    },
    "e1": {
      "from": "coord",
      "to": "pa",
      "fromSide": "right",
      "toSide": "left",
      "label": "1 prepare - vote YES - 2 COMMIT",
      "color": "green"
    },
    "e2": {
      "from": "coord",
      "to": "pb",
      "fromSide": "right",
      "toSide": "left",
      "color": "green"
    },
    "e3": {
      "from": "coord",
      "to": "pc",
      "fromSide": "right",
      "toSide": "left",
      "label": "1 prepare - vote YES - 2 ...silence",
      "color": "red",
      "style": "dashed",
      "animated": true
    }
  },
  "boxes": {
    "b1": {
      "x": 640,
      "y": -20,
      "w": 340,
      "h": 660,
      "label": "all three commit, or none — that's the promise",
      "color": "blue",
      "opacity": 0.04
    }
  },
  "texts": {
    "t1": {
      "x": 20,
      "y": 460,
      "text": "phase 1 — PREPARE: each participant durably\nstages the write, takes locks, and votes.\nA YES vote is a binding promise: 'I can\ncommit this even if I crash and restart.'",
      "color": "green",
      "size": 12
    },
    "t2": {
      "x": 20,
      "y": 590,
      "text": "phase 2 — COMMIT/ABORT: the coordinator logs\nthe decision, then tells everyone. Unanimous\nYES means commit. Any NO or timeout means abort.",
      "color": "green",
      "size": 12
    },
    "t3": {
      "x": 350,
      "y": 640,
      "text": "the blocking problem: C voted YES and now the coordinator is gone.\nC cannot commit (maybe the decision was abort) and cannot abort\n(maybe A and B already committed). It holds locks — possibly for\nminutes — and everything queued behind those rows waits with it.",
      "color": "red",
      "size": 12
    }
  },
  "meta": {
    "createdAt": "2026-07-17T09:00:00.000Z",
    "modifiedAt": "2026-07-17T09:00:00.000Z"
  }
}