PNCounter
A counter that can go up or down. Two GCounters under the hood — one for increments, one for decrements. The current value is the difference.
Converges to: inc.value - dec.value, where each half is a GCounter that only ever grows.
Worked example — live vote tally over two peers
PNCounter + Quilter is the natural fit for a vote tally: each peer owns its own slot, increments record upvotes, decrements record downvotes. Deltas propagate automatically; both replicas converge to the same net count.
See QuilterSamples.sampleVoteTally and the full integration test at VoteTallyTest.kt.
Merge rule
A PNCounter is two independent GCounters in a product lattice — one for increments (inc), one for decrements (dec). Joining two PNCounters joins each half separately. Idempotent, commutative, associative by the same argument that holds for GCounter.
There is no floor at zero. A replica can decrement without having incremented — value can go negative.
Code example
When to use
Need | Use |
|---|---|
Concurrent add/remove of an integer, any sign |
|
Shared budget that must never go negative |
|
Only ever counts up |
|