/* Remove the 'key' from the list of blocked keys for a given client. * * The function returns 1 when there are no longer blocking keys after * the current one was removed (and the client can be unblocked). */ int dontWaitForSwappedKey(redisClient *c, robj *key) { list *l; listNode *ln; listIter li; struct dictEntry *de; /* The key object might be destroyed when deleted from the c->io_keys * list (and the "key" argument is physically the same object as the * object inside the list), so we need to protect it. */ incrRefCount(key); /* Remove the key from the list of keys this client is waiting for. */ listRewind(c->io_keys,&li); while ((ln = listNext(&li)) != NULL) { if (equalStringObjects(ln->value,key)) { listDelNode(c->io_keys,ln); break; } } redisAssert(ln != NULL); /* Remove the client form the key => waiting clients map. */ de = dictFind(c->db->io_keys,key); redisAssert(de != NULL); l = dictGetEntryVal(de); ln = listSearchKey(l,c); redisAssert(ln != NULL); listDelNode(l,ln); if (listLength(l) == 0) dictDelete(c->db->io_keys,key); decrRefCount(key); return listLength(c->io_keys) == 0; }
/* Delete an element with matching score/object from the skiplist. */ int zslDelete(zskiplist *zsl, double score, robj *obj) { zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; int i; x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && compareStringObjects(x->level[i].forward->obj,obj) < 0))) x = x->level[i].forward; update[i] = x; } /* We may have multiple elements with the same score, what we need * is to find the element with both the right score and object. */ x = x->level[0].forward; if (x && score == x->score && equalStringObjects(x->obj,obj)) { zslDeleteNode(zsl, x, update); zslFreeNode(x); return 1; } else { return 0; /* not found */ } return 0; /* not found */ }
/* Watch for the specified key */ void watchForKey(redisClient *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { wk = listNodeValue(ln); if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } /* This key is not already watched in this DB. Let's add it */ clients = dictFetchValue(c->db->watched_keys,key); if (!clients) { clients = listCreate(); dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } listAddNodeTail(clients,c); /* Add the new key to the lits of keys watched by this client */ wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }
/* 比较给定的模式a和模式b是否相同,如果相同返回1,否则返回0 */ int listMatchPubsubPattern(void *a, void *b) { pubsubPattern *pa = a, *pb = b; // 模式订阅的客户端相同,且被订阅的模式也相同 return (pa->client == pb->client) && (equalStringObjects(pa->pattern,pb->pattern)); }
/* Compare the given object with the entry at the current position. */ int listTypeEqual(listTypeEntry *entry, robj *o) { listTypeIterator *li = entry->li; if (li->encoding == REDIS_ENCODING_ZIPLIST) { redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW); return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr)); } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) { return equalStringObjects(o,listNodeValue(entry->ln)); } else { redisPanic("Unknown list encoding"); } }
/* * 监视给定 key * * T = O(N) */ void watchForKey(redisClient *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ // 检查该 key 是否已经被 WATCH // (出现在 WATCH 命令调用时一个 key 被输入多次的情况) // 如果是的话,直接返回 // O(N) listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { wk = listNodeValue(ln); if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } // key 未被监视 // 根据 key ,将客户端加入到 DB 的监视 key 字典中 /* This key is not already watched in this DB. Let's add it */ // O(1) clients = dictFetchValue(c->db->watched_keys,key); if (!clients) { clients = listCreate(); dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } listAddNodeTail(clients,c); // 将 key 添加到客户端的监视列表中 /* Add the new key to the lits of keys watched by this client */ // O(1) wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }
/* Find the rank for an element by both score and key. * Returns 0 when the element cannot be found, rank otherwise. * Note that the rank is 1-based due to the span of zsl->header to the * first element. */ unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) { zskiplistNode *x; unsigned long rank = 0; int i; x = zsl->header; for (i = zsl->level-1; i >= 0; i--) { while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && compareStringObjects(x->level[i].forward->obj,o) <= 0))) { rank += x->level[i].span; x = x->level[i].forward; } /* x might be equal to zsl->header, so test if obj is non-NULL */ if (x->obj && equalStringObjects(x->obj,o)) { return rank; } } return 0; }
// WATCH 某个 KEY void watchForKey(redisClient *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ // 所有被 WATCHED 的 KEY 都被放在 redisClient.watched_keys 链表中 // 遍历这个链表,查看这个 KEY 是否已经处于监视状态(WATCHED) listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { wk = listNodeValue(ln); if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } /* This key is not already watched in this DB. Let's add it */ // 如果 KEY 还没有被 WATCH 过,那么对它进行 WATCH clients = dictFetchValue(c->db->watched_keys,key); if (!clients) { // 如果 clients 链表不存在 // 说明这个客户端是第一个监视这个 DB 的这个 KEY 的客户端 // 那么 clients 创建链表,并将它添加到 c->db->watched_keys 字典中 clients = listCreate(); dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } // 将客户端添加到 clients 链表 listAddNodeTail(clients,c); /* Add the new key to the lits of keys watched by this client */ // 除了 c->db->watched_keys 之外 // 还要将被 WATCH 的 KEY 添加到 c->watched_keys wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }
// 让client监视所有的指定的key void watchForKey(client *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ listRewind(c->watched_keys,&li); // 遍历客户端监视的键的链表,检查是否已经监视了指定的键 while((ln = listNext(&li))) { wk = listNodeValue(ln); // 如果键已经被监视,则直接返回 if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } /* This key is not already watched in this DB. Let's add it */ // 如果数据库中该键没有被client监视则添加它 clients = dictFetchValue(c->db->watched_keys,key); // 没有被client监视 if (!clients) { // 创建一个空链表 clients = listCreate(); // 值是被client监控的key,键是client,添加到数据库的watched_keys字典中 dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } // 将当前client添加到监视该key的client链表的尾部 listAddNodeTail(clients,c); /* Add the new key to the list of keys watched by this client */ // 将新的被监视的key和与该key关联的数据库加入到客户端的watched_keys中 wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }
int listMatchObjects(void *a, void *b) { return equalStringObjects(a,b); }
/* Watch for the specified key * * 让客户端 c 监视给定的键 key */ void watchForKey(redisClient *c, robj *key) { list *clients = NULL; listIter li; listNode *ln; watchedKey *wk; /* Check if we are already watching for this key */ // 检查 key 是否已经保存在 watched_keys 链表中, // 如果是的话,直接返回 listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { wk = listNodeValue(ln); if (wk->db == c->db && equalStringObjects(key,wk->key)) return; /* Key already watched */ } // 键不存在于 watched_keys ,添加它 // 以下是一个 key 不存在于字典的例子: // before : // { // 'key-1' : [c1, c2, c3], // 'key-2' : [c1, c2], // } // after c-10086 WATCH key-1 and key-3: // { // 'key-1' : [c1, c2, c3, c-10086], // 'key-2' : [c1, c2], // 'key-3' : [c-10086] // } /* This key is not already watched in this DB. Let's add it */ // 检查 key 是否存在于数据库的 watched_keys 字典中 clients = dictFetchValue(c->db->watched_keys,key); // 如果不存在的话,添加它 if (!clients) { // 值为链表 clients = listCreate(); // 关联键值对到字典 dictAdd(c->db->watched_keys,key,clients); incrRefCount(key); } // 将客户端添加到链表的末尾 listAddNodeTail(clients,c); /* Add the new key to the list of keys watched by this client */ // 将新 watchedKey 结构添加到客户端 watched_keys 链表的表尾 // 以下是一个添加 watchedKey 结构的例子 // before: // [ // { // 'key': 'key-1', // 'db' : 0 // } // ] // after client watch key-123321 in db 0: // [ // { // 'key': 'key-1', // 'db' : 0 // } // , // { // 'key': 'key-123321', // 'db': 0 // } // ] wk = zmalloc(sizeof(*wk)); wk->key = key; wk->db = c->db; incrRefCount(key); listAddNodeTail(c->watched_keys,wk); }