redis---scan

319 阅读2分钟

1、Redis的一些基本数据结构

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). */
    int refcount;
    void *ptr;
} robj;

typedef struct redisDb {
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    int id;                     /* Database ID */
    long long avg_ttl;          /* Average TTL, just for stats */
} redisDb;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

2、scan的实现

命令:scan 0 [match pattern] [count 10]
1、scanCommand
    解析游标是否合法;
    不合法直接返回。
2、scanGenericCommand
    创建list;
    解析参数是否含有count、match选项;
    从c->db->dict获取到哈希表;
    遍历集合,直到‘游标为0’或‘最大迭代次数为0’或‘返回的key大于count’就停止遍历;
    将返回的keys和obj放入到一个指针数组中;
3、dictScan
    如果dict->ht[0].used + dict->ht[1].used == 0,说明数据库为空,则return;
    通过dict->rehashidx是否为-1判断数据库是否在进行rehash;
        否:直接遍历ht[0],将key添加到之前的list中;
        是:先遍历小集合,在遍历大集合
    重新计算游标返回;
    过滤元素,不符合pattern的、过期的key;
    回复客户端;
    //下面的回调忽略了无关代码
    void scanCallback(void *privdata, const dictEntry *de) {
        void **pd = (void**) privdata;
        list *keys = pd[0];
        robj *o = pd[1];
        robj *key, *val = NULL;

        if (o == NULL) {
            sds sdskey = dictGetKey(de);
            key = createStringObject(sdskey, sdslen(sdskey));
        } 
        listAddNodeTail(keys, key);
    }