Skip to content

RedisModule_ZsetRem can lead to "empty" zset keys #4859

@itamarhaber

Description

@itamarhaber

A module using only the low level zset API can easily arrive at empty keys - an unheard of thing in Redis. Of course, the author could always check the size of the zset after zrem, and delete the key if it is 0... yuck.

@antirez @dvirsky Unless I'm doing something wrong, I think this needs to be handled by Redis.

P.S. This quote is so funny :)

Empty keys will be handled correctly by doing nothing.

Minimal reproducible code example (starting to implement ZPOP):

#include "redismodule.h"

int test(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
    
    int type = RedisModule_KeyType(key);
    if (REDISMODULE_KEYTYPE_EMPTY == type) {
        RedisModule_CloseKey(key);
        RedisModule_ReplyWithNull(ctx);
        return REDISMODULE_OK;
    }

    if (REDISMODULE_KEYTYPE_ZSET != type)
    {
        RedisModule_CloseKey(key);
        RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
        return REDISMODULE_OK;
    }

    RedisModule_ZsetFirstInScoreRange(key, REDISMODULE_NEGATIVE_INFINITE, REDISMODULE_POSITIVE_INFINITE, 0, 0);

    RedisModuleString *ele = RedisModule_ZsetRangeCurrentElement(key, NULL);
    RedisModule_ZsetRangeStop(key);

    int deleted;
    RedisModule_ZsetRem(key, ele, &deleted);

    RedisModule_CloseKey(key);
    RedisModule_ReplyWithString(ctx, ele);
    return REDISMODULE_OK;
}

int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
    REDISMODULE_NOT_USED(argv);
    REDISMODULE_NOT_USED(argc);

    if (RedisModule_Init(ctx,"module",1,REDISMODULE_APIVER_1)
        == REDISMODULE_ERR) return REDISMODULE_ERR;

    if (RedisModule_CreateCommand(ctx,"test",
        test,"write",1,1,1) == REDISMODULE_ERR)
        return REDISMODULE_ERR;

    return REDISMODULE_OK;
}

Terminal session:

127.0.0.1:6379> TYPE z
none
127.0.0.1:6379> TEST z
(nil)
127.0.0.1:6379> ZADD z 0 a 1 b
(integer) 2
127.0.0.1:6379> TYPE z
zset
127.0.0.1:6379> TEST z
"a"
127.0.0.1:6379> TYPE z
zset
127.0.0.1:6379> TEST z
"b"
127.0.0.1:6379> TYPE z
zset
127.0.0.1:6379> ZCARD z
(integer) 0
127.0.0.1:6379> EXISTS z
(integer) 1
127.0.0.1:6379> TEST z
Could not connect to Redis at 127.0.0.1:6379: Connection refused

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions