Map + dispatch, no locks needed

Before the code: what a key-value store actually is

So far the server understands the Redis language but has nothing to remember. Time to give it a brain. The brain is a JavaScript Map that lives in memory, plus a small companion table of timers for keys that should disappear on their own. That is the whole Redis storage model, in plain English. Because Node runs one callback at a time, you do not need any locks. The rest of this module wires SET, GET, DEL, and EXPIRE into that Map.

The store, with and without timers

A plain Map remembers forever. A Map plus a timer table is what makes Redis a cache, a session store, and a rate limiter.

Quiz: Quiz

Loading practice…

In Python and Go we needed locks around the KV map. In Node, the event loop runs one callback at a time. data events queue up, never interleave. STORE.set + STORE.get is safe without any synchronization.

03-get-set/server.mjs
javascript
const encodeSimple = (s) => Buffer.from(`+${s}\r\n`);
const encodeError = (s) => Buffer.from(`-${s}\r\n`);
const encodeBulk = (s) => s === null ? Buffer.from("$-1\r\n") : Buffer.from(`$${Buffer.byteLength(s)}\r\n${s}\r\n`);
const encodeArray = (items) => Buffer.concat([Buffer.from(`*${items.length}\r\n`), ...items.map(encodeBulk)]);

The reply side of RESP. parseResp turned bytes into values; these four one-liners turn values back into bytes. Note the $-1 nil case in encodeBulk, and how encodeArray builds on it.

03-get-set/server.mjs
javascript
const STORE = new Map();

const COMMANDS = {
  PING: (args) => args.length === 0 ? encodeSimple("PONG") : encodeBulk(args[0]),
  SET: (args) => {
    if (args.length < 2) return encodeError("ERR wrong number of arguments for 'set'");
    STORE.set(args[0], args[1]);
    return encodeSimple("OK");
  },
  GET: (args) => {
    if (args.length !== 1) return encodeError("ERR wrong number of arguments for 'get'");
    return encodeBulk(STORE.get(args[0]) ?? null);
  },
  ...
};

Dispatch object. Each handler returns Buffer. STORE is a plain Map. No mutex anywhere.

You cannot use multiple CPU cores from one Node process. Real Node deployments run multiple processes (via PM2, cluster module, or container replicas), one per core. The single-threaded model lets you skip locks within a process; multi-process lets you use the rest of the machine.