MediumPro challengePythonJavaScriptTypeScript
System Design — PN-Counter (CRDT)
System DesignDistributed SystemsCRDT
A shared "likes" counter replicated in several data centres that must accept writes while
partitioned and still converge — without locks or a leader. That is a CRDT (conflict-free
replicated data type).
A PN-counter keeps two grow-only maps per replica: p (increments) and n (decrements),
each mapping a replica name to a count. A replica only ever increases its own entry.value = sum(p) - sum(n). Merging two replicas takes the element-wise maximum of both maps,
which is commutative, associative and idempotent — so replicas converge in any merge order.
solve(args, ops) builds new PNCounter(replicas) — args = [replicas], the list of replica
names, every replica starting empty — and replays ops:
inc(replica, n)/dec(replica, n)— that replica countsnmore increments / decrements.
Return nothing.
merge(dst, src)—dstabsorbssrc's state (srcis unchanged). Returns nothing.value(replica)— the replica's current value.
Example — replicas ["a","b"]
inc(a,5) inc(b,3) value(a) → 5 merge(a,b) value(a) → 8 dec(a,2) value(a) → 6Sample tests
Test #1Concurrent updates converge
Input: [[["a","b"]],[["inc","a",5],["inc","b",3],["value","a"],["value","b"],["merge","a","b"],["value","a"],["dec","a",2],["value","a"],["merge","b","a"],["value","b"],["merge","b","a"],["value","b"],["dec","b",1],["inc","a",1],["merge","a","b"],["merge","b","a"],["value","a"],["value","b"]]]
Output: [null,null,5,3,null,8,null,6,null,6,null,6,null,null,null,null,6,6]
Test #2Three replicas gossip
Input: [[["x","y","z"]],[["inc","x",1],["inc","y",2],["inc","z",3],["merge","x","y"],["merge","x","z"],["merge","y","x"],["merge","z","y"],["value","x"],["value","y"],["value","z"]]]
Output: [null,null,null,null,null,null,null,6,6,6]
Test #3The value can go negative
Input: [[["a"]],[["dec","a",4],["value","a"],["inc","a",1],["value","a"]]]
Output: [null,-4,null,-3]