# Exercise 1: Pick the right cache for three real systems

You're the engineer responsible for caching architecture across three unrelated systems at a mid-size company. For each system below, decide **Redis or Memcached**, and justify the decision using specific mechanical properties from `cache_redis_theory.md`, `cache_memcached_theory.md`, and `cache_redis_vs_memcached_theory.md` — not vague appeals to "Redis is more powerful."

## System A: Rendered page-fragment cache for a news site

- Caches fully-rendered HTML fragments (article bodies, ~20-80KB each) keyed by `article:{id}:{lang}`.
- Read-heavy: ~50,000 reads/sec at peak, writes only when an article is published or edited (a few hundred/day).
- A cache miss just means re-rendering from the CMS database — mildly slower response, no correctness issue.
- The ops team wants to run this on a single beefy 32-core box and get as much raw throughput per dollar as possible; they explicitly do not want to operate a clustered/replicated system for this.
- Nobody needs to query or manipulate the cached data server-side — it's write-once-per-edit, read-many, whole-blob only.

## System B: Real-time multiplayer game leaderboard + session store

- Needs a live top-100 leaderboard, re-ranked on every score change (~5,000 score updates/sec), served to a "current rank" widget for every online player.
- Also stores session state per connected player (small hash: `hp`, `position`, `inventory_ids`), updated field-by-field many times per second per player.
- If the cache process restarts mid-event, losing the leaderboard entirely would be a visible, embarrassing incident — some tolerance for a small data-loss window is fine, total loss is not.
- Occasionally needs to publish a "player leveled up" event that a separate notification service picks up in real time.

## System C: Ephemeral idempotency-key store for a payment API

- Every incoming payment request carries a client-generated idempotency key; the API stores `idempotency:{key} -> response_body` for exactly 24 hours so a retried request returns the original response instead of double-charging.
- Extremely simple access pattern: `SETNX`-style "set if not exists" on write, plain `GET` on read, nothing else.
- Must NEVER serve a key past its 24-hour window (stale idempotency responses are a correctness bug, not just a perf issue).
- If the store restarts and loses everything, the worst case is a few double-processed requests during the outage window right after restart — undesirable, but not catastrophic, and already mitigated by other systems.

## Deliverables

1. For each system (A, B, C), state your choice: Redis or Memcached.
2. For each choice, list the **specific mechanical properties** (from the theory files) that drove the decision — cite at least two per system (e.g. "strict LRU per slab class," "selectable eviction policy," "single-threaded atomicity," "no built-in pub/sub," "slab allocation avoids fragmentation for many small session hashes," etc.).
3. For System B specifically, explain why a plain Memcached `incr`/`decr` could NOT implement the leaderboard re-ranking requirement, referencing the actual data type gap.
4. For System C specifically, explain whether Memcached's lack of a selectable eviction policy (strict LRU only) creates any real risk of a key being evicted before its 24-hour TTL under memory pressure — and what operational mitigation (unrelated to switching to Redis) would reduce that risk if Memcached were still chosen.
5. Pick ONE of the three systems and write the two or three actual client-library calls (Redis or Memcached, your choice from #1) that would implement its core read/write path — pseudocode-level API calls are fine, but they must use the real command/method names from the theory files (e.g. `ZADD`, `HINCRBY`, `add`, `cas`), not invented ones.
