Maintain algorithmic invariants

When implementing algorithms that depend on “current state” (client context, cached slot/client, etc.) or on custom data structures (stack/heap modes), make the invariant explicit and ensure all computations are derived from the specific operand/object being processed—not from incidental outer execution context.

copy reviewer prompt

Prompt

Reviewer Prompt

When implementing algorithms that depend on “current state” (client context, cached slot/client, etc.) or on custom data structures (stack/heap modes), make the invariant explicit and ensure all computations are derived from the specific operand/object being processed—not from incidental outer execution context.

Practical rules:

  • Operand over incidental context: in nested execution (e.g., MULTI/EXEC where commands run while other client state is active), compute shard slot / routing from the key/channel argument itself and do not rely on cached “current_client”/slot.
  • Encode ownership & storage mode: for DSs with multiple backing stores (stack vs heap), clearly define what is owned/freed, what is never freed, and when heap allocation happens.
  • Allocation discipline: in Redis core, use Redis allocator wrappers (zmalloc/zrealloc/zfree), not libc allocation.
  • Ergonomics that reduce misuse: prefer DS shapes that make correct usage easy (e.g., embed a small fixed buffer variant like SmallVector rather than forcing callers to manage extra stack buffers), and keep the API naming consistent with Redis style.

Example (stack-embedded “small vector” idea):

// SmallVector-like: small fixed buffer embedded in the DS.
typedef struct vec {
    size_t size;
    size_t cap;
    void **data;
    void *small[VEC_DEFAULT_INITCAP];
} vec;

void vecInit(vec *v, size_t hint) {
    v->size = 0;
    if (hint <= VEC_DEFAULT_INITCAP) {
        v->data = v->small;
        v->cap = VEC_DEFAULT_INITCAP;
    } else {
        v->data = zmalloc(sizeof(void*) * hint);
        v->cap = hint;
    }
}

void vecDestroy(vec *v) {
    if (v->data != v->small) zfree(v->data);
}

Apply this mindset to both algorithmic routing decisions and DS implementations: correctness comes from invariants tied to the actual data being acted upon, and API/structure choices that prevent accidental reliance on stale execution-context or ambiguous ownership.

Source discussions