Skip to content

Step 1 of 3 · Reading · ~2 min

Atomic Counters

String Commands

INCR & DECR — Atomic Counters

INCR is one of Redis's most-used commands in practice — rate limiters, view counters, unique ID generators all lean on it. The interesting part isn't the arithmetic; it's what "atomic" buys you and how you handle the type coercion between "a string in a string-only store" and "an integer you can do math on."

Values are strings; INCR interprets them as integers

Recall from the SET/GET lesson that everything in store is a string. INCR doesn't change that storage model — it reads the string, parses it as a base-10 integer, adds one, and writes the result back as a string:

python

INCRBY/DECRBY are the same operation parameterized by an amount instead of a fixed step of 1:

python

DECR/DECRBY are INCR/INCRBY with the sign flipped — implement one in terms of the other rather than duplicating logic.

Missing key defaults to 0

INCR counter on a key that has never been set should behave exactly as if counter held "0" — the result is 1, and the key now exists holding "1". This is different from an error; a missing key is a valid starting point, not a failure.

Why "atomic" is the whole point

If a client had to GET, add 1 in its own code, then SET the result, two concurrent clients could both read 5, both compute 6, and both write 6 — losing an increment. INCR avoids this entirely by doing the read-modify-write inside a single command that your single-threaded command loop executes without interruption. This is the same atomicity guarantee you relied on for SET NX — it's a recurring theme in Redis's design: push compound operations into the server so clients can't race each other.

Edge cases

  • Non-integer values: SET key hello then INCR key must return -ERR value is not an integer or out of range\r\n — don't let a Python int("hello") ValueError leak as an unhandled exception or a generic error message; the wording is tested precisely.
  • Overflow: real Redis operates on 64-bit signed integers and errors on overflow; depending on your test suite's scope, you may not need to replicate the exact 64-bit boundary, but be aware Python's arbitrary-precision integers won't naturally raise where a real Redis server would.
  • Leading/trailing whitespace or a value like "3.0": these should also fail as "not an integer" — int("3.0") already raises in Python, which is the behavior you want; don't pre-process with float() first.
Up nextEXPIRE & TTL — Setting TimeoutsKey Expiry

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…