1Show the Level 1 solution
2**A.**
31. **Eventual.** A few seconds behind is harmless.
42. **Strong.** Two people mustn't book the same seat.
53. **Read-your-writes.** The editor must see their change; others can lag.
64. **Causal.** Replies never before their message.
75. **Eventual.** Recommendations can be hours old.
89**B.**
101. **False.** In a distributed system, partitions happen whether you plan for them or not. "CA" means it will behave badly (or stop) when one does.
112. **False.** The choice only applies during a partition. When the network is healthy, a system can be both consistent and available (paying latency, per PACELC).
123. **False.** It makes reads usually see the latest write, but concurrent and partially failed writes and sloppy quorums can still break linearizability.
Show the Level 2 solution
1. At least **122 ms** per write (120 ms round trip plus about 2 ms local work), instead of 2 ms. Three in a row: about **366 ms**.
2. 5 nodes need 3 for a majority, so **2** can fail. 6 nodes need 4, so still only **2** can fail: the sixth node adds cost but no extra tolerance.
3. Pairs with W + R > 3: (1, 3), (2, 2), (3, 1), (2, 3), (3, 2), (3, 3). With one replica down only two are up, so W and R must each be ≤ 2 to work. **(1, 3)**, **(2, 2)** and **(2, 3)** still accept writes, but (1, 3) and (2, 3) can't read (R = 3 needs three). Only **(2, 2)** keeps both reads and writes working.
4. 20 × 30 = **600 spends** refused (users see "try again shortly"), in exchange for zero overspending.
1Show the Level 3 solution
2Tested solution (Python 3), the key parts:
34```python
5class Pair:
6 def __init__(self, mode):
7 self.mode = mode # "CP" or "AP"
8 self.a, self.b = Replica("mumbai"), Replica("frankfurt")
9 self.partitioned, self.time = False, 0
1011 def write(self, replica, key, value):
12 self.time += 1
13 if self.partitioned and self.mode == "CP":
14 raise Unavailable(f"{replica.name}: can't reach the other replica, refusing the write")
15 replica.data[key], replica.clock[key] = value, self.time
16 if not self.partitioned: # copy to the other side while connected
17 o = self.other(replica)
18 o.data[key], o.clock[key] = value, self.time
192021class GCounter:
22 def __init__(self, me):
23 self.me, self.counts = me, {}
2425 def incr(self, n=1):
26 self.counts[self.me] = self.counts.get(self.me, 0) + n
2728 def merge(self, other): # max per replica: nothing is lost
29 for k, v in other.counts.items():
30 self.counts[k] = max(self.counts.get(k, 0), v)
3132 def value(self):
33 return sum(self.counts.values())
34```
3536All checks pass: CP refuses during the partition; AP diverges; last-write-wins keeps "Now reads poetry" and loses the Mumbai edit; the counter CRDT ends at 3 + 5 = **8** on both sides. The full file is in `code/ch16_consistency.py`.
1Show the Level 4 solution
2**The bug:** the wallet runs in **AP mode**, so during a partition each region checks and updates its **own copy** of the balance.
341. Before the partition, both regions have ₹500.
52. The link breaks.
63. In Mumbai, a ₹400 purchase reads ₹500, writes ₹100, succeeds.
74. In Frankfurt, a ₹400 purchase also reads **₹500** (it hasn't heard about Mumbai), writes ₹100, succeeds.
85. ₹800 was spent from a ₹500 card. When the link heals, last-write-wins makes both show ₹100, hiding the problem until finance reconciles.
910**The fix:** money decisions need **strong consistency**. Give each card one authoritative copy (a single home-region leader, or a consensus-based store) and run the check and update together there, as one transaction. During a partition, the side that can't reach the authority **refuses** (`Unavailable`): users see "Gift card payments are temporarily unavailable, please try again shortly", and can still pay by other methods. In the tested demo, CP mode allows the first ₹400 and refuses the second.
1Show the Level 5 (sketch) solution
21. **Wallet:** strong. Each card has a home region (where it was bought); spends go to that region's leader, in one transaction with the balance check. Display balances may come from a local replica.
32. **Stock:** eventual for the "only 3 left" label (cached, from replicas); strong for the checkout check, a conditional decrement on the leader (Chapter 17).
43. **Profile and cart:** read-your-writes (route the user's reads to the leader for a short time after writes, or by log position); monotonic reads by sticking users to a replica.
54. **Comments and replies:** causal: write a thread's comments through one leader (or partition by thread) so replies replicate after their parent.
65. **View counters and trending:** eventual, with counter CRDTs or per-region counters summed in the background.
76. **Frankfurt during a 10-minute partition:** browsing, likes, trending and the "only N left" label keep working (possibly stale); a user's own profile edits work if Frankfurt holds their home copy, otherwise they're queued or refused; wallet spends and checkout for Mumbai-homed data are refused with a clear message; comments may be delayed but never shown out of order.