Repository: valkey-io/valkey
File: src/server.c (C)

Code before:
    getKeysSubcommandImpl(c, 0);
}

/* Invalidate the cached COMMAND response when command table changes */
void invalidateCommandCache(void) {
    for (int i = 0; i < RESP_CACHE_INDEX_MAX; i++) {
        if (server.command_response_cache[i]) {
            sdsfree(server.command_response_cache[i]);
            server.command_response_cache[i] = NULL;
        }
    }
}

/* Generate and cache the full COMMAND response */
static void cacheCommandResponse(int resp) {
    client *caching_client = createCachedResponseClient(resp);
    
    hashtableIterator iter;
    void *next;
    addReplyArrayLen(caching_client, hashtableSize(server.commands));
    hashtableInitIterator(&iter, server.commands, 0);
    while (hashtableNext(&iter, &next)) {
        struct serverCommand *cmd = next;
        addReplyCommandInfo(caching_client, cmd);
    }
    hashtableResetIterator(&iter);
    
    server.command_response_cache[RESP_CACHE_INDEX(resp)] = aggregateClientOutputBuffer(caching_client);
    
    deleteCachedResponseClient(caching_client);
}

/* COMMAND (no args) */
void commandCommand(client *c) {
    /* Use cached response if available for the client's protocol version */
    int cache_idx = RESP_CACHE_INDEX(c->resp);
    sds cache = server.command_response_cache[cache_idx];
    
    if (cache == NULL) {
        cacheCommandResponse(c->resp);
        cache = server.command_response_cache[cache_idx];
    }
    
    addReplyProto(c, cache, sdslen(cache));
}

/* COMMAND COUNT */
void commandCountCommand(client *c) {
    addReplyLongLong(c, hashtableSize(server.commands));
}


Review comment (performance):
Here we rely on cacheCommandResponse populating a specific global and then we fetch it afterwards. It looks like an implicit dependency that we can avoid.

Consider returning the response from cachecCommandResponse, like we do in generateClusterSlotResponse, and where the corresponding call looks like this:

```C
    sds cached_reply = server.cached_cluster_slot_info[conn_type];
    if (!cached_reply) {
        cached_reply = generateClusterSlotResponse(c->resp);
        server.cached_cluster_slot_info[conn_type] = cached_reply;
    }
```

Code after:
    deleteCachedResponseClient(caching_client);
    return command_response;
}

int verifyCachedCommandResponse(sds cached_response, int resp) {
    sds generated_response = generateCommandResponse(resp);
    int is_equal = !sdscmp(generated_response, cached_response);
    /* Here, we use LL_WARNING so this gets printed when debug assertions are enabled and the system is about to crash. */
    if (!is_equal)
        serverLog(LL_WARNING, "\ngenerated_response:\n%s\n\ncached_response:\n%s", generated_response, cached_response);
    sdsfree(generated_response);
    return is_equal;
}

/* COMMAND (no args) */
void commandCommand(client *c) {
    /* Use cached response if available for the client's protocol version */
    int cache_idx = RESP_CACHE_INDEX(c->resp);
    sds cache = server.command_response_cache[cache_idx];

    if (!cache) {
        cache = generateCommandResponse(c->resp);
        server.command_response_cache[cache_idx] = cache;
    } else {
        debugServerAssertWithInfo(c, NULL, verifyCachedCommandResponse(cache, c->resp));
    }

    addReplyProto(c, cache, sdslen(cache));
}

/* COMMAND COUNT */
void commandCountCommand(client *c) {
    addReplyLongLong(c, hashtableSize(server.commands));
}

typedef enum {
    COMMAND_LIST_FILTER_MODULE,
    COMMAND_LIST_FILTER_ACLCAT,
    COMMAND_LIST_FILTER_PATTERN,
} commandListFilterType;

typedef struct {
    commandListFilterType type;
    sds arg;
    struct {
        int valid;
        union {
            uint64_t aclcat;
            void *module_handle;
        } u;
    } cache;