Frontend Labs
⋯

34. Redis: the ae.c event loop, sds dynamic strings, object encoding

What it is: an in-memory data-structure server, written by Salvatore Sanfilippo (also kilo's author, Section 25) — single-threaded for all command execution, which sidesteps Section 20's entire locking problem by design.

Concept mapping:

  • ae.c, Redis's event loop, is Section 23.2's select()-based chat server, generalized: it abstracts over epoll (Linux), kqueue (macOS/BSD), and select (fallback) behind one API (aeCreateFileEvent, aeMain), exactly the way SQLite's VFS abstracts over filesystems. This single-threaded event loop, not a thread pool, is why Redis commands are atomic without any mutex: only one command ever executes at a time, so Section 20's entire race-condition class simply cannot occur in command logic.
  • sds (Simple Dynamic Strings), sds.h/sds.c, is Section 7's "a string is a convention" problem, solved once, everywhere in the codebase: an sds is a char * (so it's still compatible with every libc string function), but the bytes before that pointer hold a header with the length and allocated capacity — the same "hidden header before the returned pointer" trick real allocators use internally (Section 39).
// simplified sketch of the real sds design
struct sdshdr {
    uint32_t len;     // used length — makes strlen() O(1) instead of O(n)
    uint32_t alloc;   // allocated capacity — makes "do we need to grow?" O(1)
    char     buf[];   // C99 flexible array member — the actual string bytes
};
// sdsnew() returns &hdr->buf[0], NOT &hdr — so callers use it exactly like char*,
// while sdslen(s) reaches backward: ((struct sdshdr*)(s - sizeof(struct sdshdr)))->len

This flexible-array-member technique (buf[] as the struct's last member, with the actual allocation sized to sizeof(struct sdshdr) + needed_bytes) is standard C99 and appears constantly in real systems code for exactly this "one allocation, header + variable-length payload" shape.

  • Object encoding: Redis's robj uses Section 8.3's tagged-union pattern — a type field plus an encoding field that says whether a "list" is currently a compact ziplist (few, small elements) or a full linked list (many elements), transparently upgrading as it grows. This is the real-world justification for tagged unions: pick the cheapest representation that fits the current data, dispatch on the tag everywhere you touch it.

Generated from real-life-c-guide.md · 8 Oct 2026 16:36