A deep-dive into how Redis handles client command parsing and response buffering.
The query buffer is an SDS (Simple Dynamic String), Redis's custom string library. It automatically grows to accommodate incoming data from the client's socket. This single buffer is highly efficient as it minimizes the number of `read()` syscalls needed.
(sds)A single, dynamic string that grows as data arrives from the socket. Redis parses commands directly from this buffer.
Represents the total number of bytes currently stored in the query buffer, equivalent to its string length. This is the `qbuf` field you see in the `CLIENT LIST` command.
: 0The amount of pre-allocated, unused space at the end of the SDS string. SDS strings often allocate more memory than needed to avoid frequent reallocations on growth, and this value shows that extra capacity. It corresponds to `qbuf-free` in `CLIENT LIST`.
: 0The "query buffer position". This is a crucial field that marks how far Redis has parsed into the buffer. Instead of deleting processed data immediately (which is slow), Redis just advances this position marker. The buffer is only trimmed later for efficiency.
: 0Tracks the maximum size the query buffer has reached since the client connected. This is useful for monitoring and debugging clients that might be sending unusually large commands.
: 0Represents the internal state of the client connection. This simulation shows:
> Log messages will appear here.
A pointer to a fixed-size buffer allocated when a client connects. Redis writes small replies here to completely avoid the overhead of a `malloc` call, which is a major performance win for common, short commands (like OK, PONG, integer replies).
(char[16384])A fixed-size static buffer for small replies. Avoids `malloc` overhead for common cases. _addReplyToBuffer()
An integer that acts as a position marker or offset. It tracks how many bytes have been written into the static `buf` so far. When `bufpos` equals the buffer's size, it's full.
: 0This is a compile-time constant, typically 16KB. It's chosen to be large enough to handle the vast majority of Redis command replies without needing a heap allocation, but small enough not to waste memory for thousands of connected clients.
: 16384A pointer to a doubly linked list. When the static buffer overflows, Redis allocates reply blocks on the heap and appends them to this list. Appending to the tail is an O(1) operation, making it extremely fast.
// Simplified C structure for each block
typedef struct clientReplyBlock {
size_t size; // Total allocated size of buf
size_t used; // Bytes currently used in buf
char buf[]; // Flexible array holding reply data
} clientReplyBlock;
(list *)
A linked list of heap-allocated blocks for large or subsequent replies. Enables efficient `writev()` syscall. _addReplyProtoToList()
This shows the number of separate heap-allocated blocks in the dynamic list. The size of each block is variable:
PROTO_REPLY_CHUNK_BYTES) is created to accommodate future small appends without needing another `malloc`.Tracks the total *allocated memory* (not just used bytes) of all blocks in the `client->reply` list. This value is critical for enforcing the client-output-buffer-limit to prevent a slow client from consuming all the server's memory.