/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or * 0 if the client was not subscribed to the specified channel. */ int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) { listNode *ln; pubsubPattern pat; int retval = 0; incrRefCount(pattern); /* Protect the object. May be the same we remove */ if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) { retval = 1; listDelNode(c->pubsub_patterns,ln); pat.client = c; pat.pattern = pattern; ln = listSearchKey(server.pubsub_patterns,&pat); listDelNode(server.pubsub_patterns,ln); } /* Notify the client */ if (notify) { addReply(c,shared.mbulkhdr[3]); addReply(c,shared.punsubscribebulk); addReplyBulk(c,pattern); addReplyLongLong(c,dictSize(c->pubsub_channels)+ listLength(c->pubsub_patterns)); } decrRefCount(pattern); return retval; }
/* Unblock a client that's waiting in a blocking operation such as BLPOP */ void unblockClientWaitingData(redisClient *c) { dictEntry *de; list *l; int j; redisAssertWithInfo(c,NULL,c->bpop.keys != NULL); /* The client may wait for multiple keys, so unblock it for every key. */ for (j = 0; j < c->bpop.count; j++) { /* Remove this client from the list of clients waiting for this key. */ de = dictFind(c->db->blocking_keys,c->bpop.keys[j]); redisAssertWithInfo(c,c->bpop.keys[j],de != NULL); l = dictGetVal(de); listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(c->db->blocking_keys,c->bpop.keys[j]); decrRefCount(c->bpop.keys[j]); } /* Cleanup the client structure */ zfree(c->bpop.keys); c->bpop.keys = NULL; if (c->bpop.target) decrRefCount(c->bpop.target); c->bpop.target = NULL; c->flags &= ~REDIS_BLOCKED; c->flags |= REDIS_UNBLOCKED; server.bpop_blocked_clients--; listAddNodeTail(server.unblocked_clients,c); }
int closeTimedoutClients(aeEventLoop *el) { if(el->myid != 0) { httpClient *c; int deletedNodes = 0; time_t now = time(NULL); listIter li; listNode *ln; listRewind(el->clients,&li); while ((ln = listNext(&li)) != NULL) { c = listNodeValue(ln); if (el->maxidletime && (now - c->lastinteraction > el->maxidletime)) { /* the client is waiting for reply */ if (c->blocked) { /* This situation happens when request_handler time exceeds client timeout. * Client timeout is typically 30 seconds and * Request_handler rarely consumes more than 1 second. * This rare case has a very small role in overall performance. */ listNode *ln = listSearchKey(c->ceList,c); if(ln) listDelNode(c->ceList,ln); } freeClient(c); deletedNodes++; } else break; } return deletedNodes; } return 0; }
/* Unblock a client that's waiting in a blocking operation such as BLPOP. * You should never call this function directly, but unblockClient() instead. */ void unblockClientWaitingData(redisClient *c) { dictEntry *de; dictIterator *di; list *l; redisAssertWithInfo(c,NULL,dictSize(c->bpop.keys) != 0); di = dictGetIterator(c->bpop.keys); /* The client may wait for multiple keys, so unblock it for every key. */ while((de = dictNext(di)) != NULL) { robj *key = dictGetKey(de); redisDb *db = &(c->db)[keyHashSlot(key->ptr, sdslen(key->ptr))]; /* Remove this client from the list of clients waiting for this key. */ l = dictFetchValue(db->blocking_keys,key); redisAssertWithInfo(c,key,l != NULL); listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(db->blocking_keys,key); } dictReleaseIterator(di); /* Cleanup the client structure */ dictEmpty(c->bpop.keys,NULL); if (c->bpop.target) { decrRefCount(c->bpop.target); c->bpop.target = NULL; } }
/* 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; }
// 取消客户端对所有的键的监视,清理 EXEC dirty 标识状态由调用者决定 void unwatchAllKeys(client *c) { listIter li; listNode *ln; // 如果客户端没有监视key则直接返回 if (listLength(c->watched_keys) == 0) return; listRewind(c->watched_keys,&li); // 遍历客户端监视的key while((ln = listNext(&li))) { list *clients; watchedKey *wk; /* Lookup the watched key -> clients list and remove the client * from the list */ wk = listNodeValue(ln); // 从数据库中的watched_keys字典中查找出监视key的client clients = dictFetchValue(wk->db->watched_keys, wk->key); serverAssertWithInfo(c,NULL,clients != NULL); // 从client的链表中删除当前client节点 listDelNode(clients,listSearchKey(clients,c)); /* Kill the entry at all if this was the only client */ // 如果client链表为空,标识给key没有被监视 if (listLength(clients) == 0) // 从数据库的watched_keys中删除该key dictDelete(wk->db->watched_keys, wk->key); /* Remove this watched key from the client->watched list */ // 从客户端的watched_keys中删除该节点 listDelNode(c->watched_keys,ln); decrRefCount(wk->key); zfree(wk); } }
/* Unblock a client that's waiting in a blocking operation such as BLPOP */ void unblockClientWaitingData(redisClient *c) { dictEntry *de; dictIterator *di; list *l; redisAssertWithInfo(c,NULL,dictSize(c->bpop.keys) != 0); di = dictGetIterator(c->bpop.keys); /* The client may wait for multiple keys, so unblock it for every key. */ while((de = dictNext(di)) != NULL) { robj *key = dictGetKey(de); /* Remove this client from the list of clients waiting for this key. */ l = dictFetchValue(c->db->blocking_keys,key); redisAssertWithInfo(c,key,l != NULL); listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(c->db->blocking_keys,key); } dictReleaseIterator(di); /* Cleanup the client structure */ dictEmpty(c->bpop.keys,NULL); if (c->bpop.target) { decrRefCount(c->bpop.target); c->bpop.target = NULL; } c->flags &= ~REDIS_BLOCKED; c->flags |= REDIS_UNBLOCKED; server.bpop_blocked_clients--; listAddNodeTail(server.unblocked_clients,c); }
/* Unblock a client that's waiting in a blocking operation such as BLPOP */ void unblockClientWaitingData(redisClient *c) { dictEntry *de; list *l; int j; redisAssert(c->blocking_keys != NULL); /* The client may wait for multiple keys, so unblock it for every key. */ for (j = 0; j < c->blocking_keys_num; j++) { /* Remove this client from the list of clients waiting for this key. */ de = dictFind(c->db->blocking_keys,c->blocking_keys[j]); redisAssert(de != NULL); l = dictGetEntryVal(de); listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ if (listLength(l) == 0) dictDelete(c->db->blocking_keys,c->blocking_keys[j]); decrRefCount(c->blocking_keys[j]); } /* Cleanup the client structure */ zfree(c->blocking_keys); c->blocking_keys = NULL; c->flags &= (~REDIS_BLOCKED); server.blpop_blocked_clients--; /* We want to process data if there is some command waiting * in the input buffer. Note that this is safe even if * unblockClientWaitingData() gets called from freeClient() because * freeClient() will be smart enough to call this function * *after* c->querybuf was set to NULL. */ if (c->querybuf && sdslen(c->querybuf) > 0) processInputBuffer(c); }
/* Unwatch all the keys watched by this client. To clean the EXEC dirty * flag is up to the caller. */ void unwatchAllKeys(redisClient *c) { listIter li; listNode *ln; if (listLength(c->watched_keys) == 0) return; listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { list *clients; watchedKey *wk; /* Lookup the watched key -> clients list and remove the client * from the list */ wk = listNodeValue(ln); clients = dictFetchValue(wk->db->watched_keys, wk->key); redisAssert(clients != NULL); listDelNode(clients,listSearchKey(clients,c)); /* Kill the entry at all if this was the only client */ if (listLength(clients) == 0) dictDelete(wk->db->watched_keys, wk->key); /* Remove this watched key from the client->watched list */ listDelNode(c->watched_keys,ln); decrRefCount(wk->key); zfree(wk); } }
void smemfreeCommand(client *c) { long long ll_var; int mem_id; int free_cnt = 0; struct smem_t * smem_p = NULL; listNode *lnode; int j; int ret; for (j = 1; j < c->argc; j++){ if(getLongLongFromObject(c->argv[j],&ll_var) == C_OK){ //serverLog(LL_WARNING,"[smemfreeCommand] get share memory id: %lld", ll_var); mem_id = ll_var; // get the item from list lnode = listSearchKey(server.smem_list_used, &mem_id); if(lnode){ // smem_p = lnode->value; smem_p->cnt--; if(smem_p->cnt <= 0){ smem_p->state = SMEM_T_STATE_AVAILAVLE; // add the item to smem_list_available smemlistMoveNode(server.smem_list_used, server.smem_list_available, lnode); /* // add for test // free the share memory ret = smem_free_buffer(mem_id); if(ret == 0){ server.share_memory_size -= smem_p->size; // delete the node listDelNode(server.smem_list_used, lnode); }else{ serverLog(LL_WARNING,"[smemfreeCommand] smem_free_buffer failed ret=%d.", ret); } */ } free_cnt ++; }else{ //serverLog(LL_WARNING,"[smemfreeCommand] not found the id(%d) in list, try to free.", mem_id); smem_free_buffer(mem_id); } } } addReplyLongLong(c,free_cnt); return C_OK; }
//解阻塞一个正在阻塞中的client void unblockClientWaitingData(client *c) { dictEntry *de; dictIterator *di; list *l; serverAssertWithInfo(c,NULL,dictSize(c->bpop.keys) != 0); //创建一个字典的迭代器,指向的是造成client阻塞的键所组成的字典 di = dictGetIterator(c->bpop.keys); /* The client may wait for multiple keys, so unblock it for every key. */ //因为client可能被多个key所阻塞,所以要遍历所有的键 while((de = dictNext(di)) != NULL) { robj *key = dictGetKey(de); //获得key对象 /* Remove this client from the list of clients waiting for this key. */ //根据key找到对应的列表类型值,值保存着被阻塞的client,从中找c->db->blocking_keys中寻找 l = dictFetchValue(c->db->blocking_keys,key); serverAssertWithInfo(c,key,l != NULL); // 将阻塞的client从列表中移除 listDelNode(l,listSearchKey(l,c)); /* If the list is empty we need to remove it to avoid wasting memory */ //如果当前列表为空了,则从c->db->blocking_keys中将key删除 if (listLength(l) == 0) dictDelete(c->db->blocking_keys,key); } dictReleaseIterator(di); //释放迭代器 /* Cleanup the client structure */ //清空bpop.keys的所有节点 dictEmpty(c->bpop.keys,NULL); //如果保存有新添加的元素,则应该释放 if (c->bpop.target) { decrRefCount(c->bpop.target); c->bpop.target = NULL; } }
/* 模式订阅,即设置客户端订阅某模式。如果订阅成功则返回1,如果客户端已经订阅了该模式则返回0。*/ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; // 先在客户端的c->pubsub_patterns链表中查找,判断客户端是否已经订阅了该模式 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { // 客户端并没有订阅该模式 retval = 1; pubsubPattern *pat; // 将制定模式添加到c->pubsub_patterns链表中 listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; // 将pubsubPattern结构添加到server.pubsub_patterns链表中 listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ // 回复客户端 addReply(c,shared.mbulkhdr[3]); // 回复“psubscribe”字符串 addReply(c,shared.psubscribebulk); // 回复被订阅的模式字符串 addReplyBulk(c,pattern); // 回复客户端订阅的频道和模式总数目 addReplyLongLong(c,clientSubscriptionsCount(c)); return retval; }
static void fts_index_del(fts_t *fts, fts_doc_t *doc) { int i, len, nonstopwords; sds *terms; terms = sds_tokenize(doc->doc->ptr, &len, &nonstopwords); if (!terms) return; for (i = 0; i < len; i++) { sds term = terms[i]; list *idx; listNode *ln; if (sdslen(term) == 0) { sdsfree(term); continue; } idx = dict_get(fts->index, term); assert(idx); ln = listSearchKey(idx, doc); assert(ln); index_item_t *idi = ln->value; idi->tf--; if (!idi->tf) listDelNode(idx, ln); sdsfree(term); } rr_free(terms); fts->len -= doc->len; }
// 撤销对这个客户端的所有 WATCH // 清除 EXEC dirty FLAG 的任务由调用者完成 void unwatchAllKeys(redisClient *c) { listIter li; listNode *ln; // 没有 WATCHED KEY ,直接返回 if (listLength(c->watched_keys) == 0) return; listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { list *clients; watchedKey *wk; /* Lookup the watched key -> clients list and remove the client * from the list */ // 将当前客户端从监视 KEY 的链表中移除 wk = listNodeValue(ln); clients = dictFetchValue(wk->db->watched_keys, wk->key); redisAssertWithInfo(c,NULL,clients != NULL); listDelNode(clients,listSearchKey(clients,c)); /* Kill the entry at all if this was the only client */ // 如果监视 KEY 的只有这个客户端 // 那么将链表从字典中删除 if (listLength(clients) == 0) dictDelete(wk->db->watched_keys, wk->key); /* Remove this watched key from the client->watched list */ // 还需要将 KEY 从 client->watched_keys 链表中移除 listDelNode(c->watched_keys,ln); decrRefCount(wk->key); zfree(wk); } }
void freeClient(void *vc) { ugClient *c = (ugClient *) vc; listNode *node = listSearchKey(server.clients, c); if (node) { listDelNode(server.clients, node); } }
int main(int argc, char *argv[]) { list *l = listCreate(); char u[] = "user1,user2,user3"; ASSERT(3 == initUserList(l, u)); ASSERT(listSearchKey(l, "user1")); ASSERT(listSearchKey(l, "user2")); ASSERT(listSearchKey(l, "user3")); ASSERT(NULL == listSearchKey(l, "user4")); /* wrong ASSERT(NULL == listSearchKey(l, "user1")); */ return OK; }
void freeClient(client *c) { listNode *ln; if (c->flags & CLIENT_BLOCKED) { if (c->bfree) c->bfree(c->bpop.data); } /* If this is marked as current client unset it */ if (server.current_client == c) server.current_client = NULL; /* Free the query buffer */ sdsfree(c->querybuf); c->querybuf = NULL; /* Close socket, unregister events, and remove list of replies and * accumulated arguments. */ if (c->fd != -1) { aeDeleteFileEvent(server.el,c->fd,AE_READABLE); aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); close(c->fd); } freeClientArgv(c); /* Remove from the list of clients */ if (c->fd != -1) { ln = listSearchKey(server.clients,c); serverAssert(ln != NULL); listDelNode(server.clients,ln); } /* If this client was scheduled for async freeing we need to remove it * from the queue. */ if (c->flags & CLIENT_CLOSE_ASAP) { ln = listSearchKey(server.clients_to_close,c); serverAssert(ln != NULL); listDelNode(server.clients_to_close,ln); } /* Release other dynamically allocated client structure fields, * and finally release the client structure itself. */ free(c->argv); free(c); }
/* Publish a message */ int smempubsubPublishMessage(robj *channel, robj *message) { int receivers = 0; dictEntry *de; listNode *ln; listIter li; int mem_id = -1; struct smem_t * smem_p = NULL; listNode *lnode = NULL; long long ll_var; /* Get the share memory id */ if(getLongLongFromObject(message,&ll_var) == C_OK){ //serverLog(LL_WARNING,"[smempubsubPublishMessage] get share memory id: %lld", ll_var); mem_id = ll_var; // get the item from list lnode = listSearchKey(server.smem_list_used, &mem_id); if(lnode){ smem_p = lnode->value; }else{ //serverLog(LL_WARNING,"[smempubsubPublishMessage] not found the id(%d) in list.", mem_id); mem_id = -1; } } /* Send to clients listening for that channel */ de = dictFind(server.smempubsub_channels,channel); if (de) { list *list = dictGetVal(de); listNode *ln; listIter li; listRewind(list,&li); while ((ln = listNext(&li)) != NULL) { client *c = ln->value; addReply(c,shared.mbulkhdr[3]); addReply(c,shared.messagebulk); addReplyBulk(c,channel); addReplyBulk(c,message); receivers++; // if message is share memory id, should increase use count if(lnode){ smem_p->cnt++; //serverLog(LL_WARNING,"[smempubsubPublishMessage] receivers:%d, smem_p->cnt=%d.", receivers, smem_p->cnt); } } } return receivers; }
/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or * 0 if the client was not subscribed to the specified channel. * * 取消客户端 c 对模式 pattern 的订阅。 * * 取消成功返回 1 ,因为客户端未订阅 pattern 而造成取消失败,返回 0 。 */ int pubsubUnsubscribePattern(redisClient *c, robj *pattern, int notify) { listNode *ln; pubsubPattern pat; int retval = 0; incrRefCount(pattern); /* Protect the object. May be the same we remove */ // 先确认一下,客户端是否订阅了这个模式 if ((ln = listSearchKey(c->pubsub_patterns,pattern)) != NULL) { retval = 1; // 将模式从客户端的订阅列表中删除 listDelNode(c->pubsub_patterns,ln); // 设置 pubsubPattern 结构 pat.client = c; pat.pattern = pattern; // 在服务器中查找 ln = listSearchKey(server.pubsub_patterns,&pat); listDelNode(server.pubsub_patterns,ln); } /* Notify the client */ // 回复客户端 if (notify) { addReply(c,shared.mbulkhdr[3]); // "punsubscribe" 字符串 addReply(c,shared.punsubscribebulk); // 被退订的模式 addReplyBulk(c,pattern); // 退订频道之后客户端仍在订阅的频道和模式的总数 addReplyLongLong(c,dictSize(c->pubsub_channels)+ listLength(c->pubsub_patterns)); } decrRefCount(pattern); return retval; }
static void freeClient(client c) { listNode *ln; aeDeleteFileEvent(config.el,c->context->fd,AE_WRITABLE); aeDeleteFileEvent(config.el,c->context->fd,AE_READABLE); redisFree(c->context); sdsfree(c->obuf); zfree(c); config.liveclients--; ln = listSearchKey(config.clients,c); assert(ln != NULL); listDelNode(config.clients,ln); }
void gwseriport_release(struct gwseriport *s) { aeDeleteFileEvent(server.el,s->fd,AE_READABLE); aeDeleteFileEvent(server.el,s->fd,AE_WRITABLE); close(s->fd); buffer_release(s->recvbuf); listNode *ln = listSearchKey(server.seriports,s); assert(ln != NULL); listDelNode(server.seriports,ln); free(s); }
/* 退订频道,即取消客户端对某频道的订阅。如果操作成功返回1,如果该客户端没有订阅该频道则返回0 */ int pubsubUnsubscribeChannel(redisClient *c, robj *channel, int notify) { dictEntry *de; list *clients; listNode *ln; int retval = 0; /* Remove the channel from the client -> channels hash table */ incrRefCount(channel); /* channel may be just a pointer to the same object we have in the hash tables. Protect it... */ // 将频道从客户端client -> channels字典中移除,如果移除成功,说明客户端的确订阅了该频道 if (dictDelete(c->pubsub_channels,channel) == DICT_OK) { retval = 1; /* Remove the client from the channel -> clients list hash table */ /* 将客户端从server.pubsub_channels字典中移除 */ // 找到订阅该频道的客户端链表 de = dictFind(server.pubsub_channels,channel); redisAssertWithInfo(c,NULL,de != NULL); clients = dictGetVal(de); // 在链表中查找该客户端 ln = listSearchKey(clients,c); redisAssertWithInfo(c,NULL,ln != NULL); // 移除客户端 listDelNode(clients,ln); // 如果订阅该频道的客户端链表为空,则删除之 if (listLength(clients) == 0) { /* Free the list and associated hash entry at all if this was * the latest client, so that it will be possible to abuse * Redis PUBSUB creating millions of channels. */ dictDelete(server.pubsub_channels,channel); } } /* Notify the client */ // 回复客户端 if (notify) { addReply(c,shared.mbulkhdr[3]); addReply(c,shared.unsubscribebulk); // 被退订的客户端 addReplyBulk(c,channel); // 客户端仍在订阅的频道和模式数量 addReplyLongLong(c,dictSize(c->pubsub_channels)+ listLength(c->pubsub_patterns)); } decrRefCount(channel); /* it is finally safe to release it */ return retval; }
/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. * * 设置客户端 c 订阅模式 pattern 。 * * 订阅成功返回 1 ,如果客户端已经订阅了该模式,那么返回 0 。 */ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; // 在链表中查找模式,看客户端是否已经订阅了这个模式 // 这里为什么不像 channel 那样,用字典来进行检测呢? // 虽然 pattern 的数量一般来说并不多 if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { // 如果没有的话,执行以下代码 retval = 1; pubsubPattern *pat; // 将 pattern 添加到 c->pubsub_patterns 链表中 listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); // 创建并设置新的 pubsubPattern 结构 pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; // 添加到末尾 listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ // 回复客户端。 // 示例: // redis 127.0.0.1:6379> PSUBSCRIBE xxx* // Reading messages... (press Ctrl-C to quit) // 1) "psubscribe" // 2) "xxx*" // 3) (integer) 1 addReply(c,shared.mbulkhdr[3]); // 回复 "psubscribe" 字符串 addReply(c,shared.psubscribebulk); // 回复被订阅的模式 addReplyBulk(c,pattern); // 回复客户端订阅的频道和模式的总数 addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns)); return retval; }
/* Subscribe a client to a pattern. Returns 1 if the operation succeeded, or 0 if the client was already subscribed to that pattern. */ int pubsubSubscribePattern(redisClient *c, robj *pattern) { int retval = 0; if (listSearchKey(c->pubsub_patterns,pattern) == NULL) { retval = 1; pubsubPattern *pat; listAddNodeTail(c->pubsub_patterns,pattern); incrRefCount(pattern); pat = zmalloc(sizeof(*pat)); pat->pattern = getDecodedObject(pattern); pat->client = c; listAddNodeTail(server.pubsub_patterns,pat); } /* Notify the client */ addReply(c,shared.mbulkhdr[3]); addReply(c,shared.psubscribebulk); addReplyBulk(c,pattern); addReplyLongLong(c,dictSize(c->pubsub_channels)+listLength(c->pubsub_patterns)); return retval; }
void smemrmCommand(client *c) { long long ll_var; int mem_id; int free_cnt = 0; struct smem_t * smem_p = NULL; listNode *lnode; int j; for (j = 1; j < c->argc; j++){ // check the size if(getLongLongFromObject(c->argv[j],&ll_var) == C_OK){ //serverLog(LL_WARNING,"get share memory id: %lld", ll_var); mem_id = ll_var; // get the item from list lnode = listSearchKey(server.smem_list_available, &mem_id); if(lnode){ smem_p = lnode->value; // update the share memory used status server.share_memory_size -= smem_p->size; //serverLog(LL_WARNING,"[smemrmCommand] rm the id(%d) in list.", mem_id); listDelNode(server.smem_list_available, lnode); }else serverLog(LL_WARNING,"[smemrmCommand] not found the id(%d) in list, try to free.", mem_id); if(!smem_free_buffer(mem_id)){ free_cnt ++; } } } addReplyLongLong(c,free_cnt); return C_OK; }
/* * 取消所有该客户端监视的 key * 对事务状态的清除由调用者执行 * * T = O(N^2) */ void unwatchAllKeys(redisClient *c) { listIter li; listNode *ln; // 没有键被 watch ,直接返回 if (listLength(c->watched_keys) == 0) return; // 从客户端以及 DB 中删除所有监视 key 和客户端的资料 // O(N^2) listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { list *clients; watchedKey *wk; /* Lookup the watched key -> clients list and remove the client * from the list */ // 取出 watchedKey 结构 wk = listNodeValue(ln); // 删除 db 中的客户端信息, O(1) clients = dictFetchValue(wk->db->watched_keys, wk->key); redisAssertWithInfo(c,NULL,clients != NULL); // O(N) listDelNode(clients,listSearchKey(clients,c)); /* Kill the entry at all if this was the only client */ if (listLength(clients) == 0) dictDelete(wk->db->watched_keys, wk->key); /* Remove this watched key from the client->watched list */ // 将 key 从客户端的监视列表中删除, O(1) listDelNode(c->watched_keys,ln); decrRefCount(wk->key); zfree(wk); } }
static bool fts_index_add(fts_t *fts, fts_doc_t *doc) { int i, len, nonstopwords; sds *terms; terms = sds_tokenize(doc->doc->ptr, &len, &nonstopwords); if (!terms) return false; for (i = 0; i < len; i++) { sds term = terms[i]; list *idx; listNode *ln; if (sdslen(term) == 0) { sdsfree(term); continue; } idx = dict_get(fts->index, term); if (!idx) { idx = index_list_create(); dict_set(fts->index, term, idx); } ln = listSearchKey(idx, doc); if (ln) { index_item_t *idi = ln->value; idi->tf++; } else { index_item_t *idi = rr_malloc(sizeof(*idi)); idi->doc = doc; idi->tf = 1; listAddNodeHead(idx, idi); } sdsfree(term); } rr_free(terms); doc->len = nonstopwords; fts->len += doc->len; return true; }
/* Unsubscribe a client from a channel. Returns 1 if the operation succeeded, or * 0 if the client was not subscribed to the specified channel. */ int smempubsubUnsubscribeChannel(client *c, robj *channel, int notify) { dictEntry *de; list *clients; listNode *ln; int retval = 0; /* Remove the channel from the client -> channels hash table */ incrRefCount(channel); /* channel may be just a pointer to the same object we have in the hash tables. Protect it... */ if (dictDelete(c->smempubsub_channels,channel) == DICT_OK) { retval = 1; /* Remove the client from the channel -> clients list hash table */ de = dictFind(server.smempubsub_channels,channel); serverAssertWithInfo(c,NULL,de != NULL); clients = dictGetVal(de); ln = listSearchKey(clients,c); serverAssertWithInfo(c,NULL,ln != NULL); listDelNode(clients,ln); if (listLength(clients) == 0) { /* Free the list and associated hash entry at all if this was * the latest client, so that it will be possible to abuse * Redis PUBSUB creating millions of channels. */ dictDelete(server.smempubsub_channels,channel); } } /* Notify the client */ if (notify) { addReply(c,shared.mbulkhdr[3]); addReply(c,shared.unsubscribebulk); addReplyBulk(c,channel); addReplyLongLong(c,dictSize(c->smempubsub_channels)); } decrRefCount(channel); /* it is finally safe to release it */ return retval; }
/* Unwatch all the keys watched by this client. To clean the EXEC dirty * flag is up to the caller. * * 取消客户端对所有键的监视。 * * 清除客户端事务状态的任务由调用者执行。 */ void unwatchAllKeys(redisClient *c) { listIter li; listNode *ln; // 没有键被监视,直接返回 if (listLength(c->watched_keys) == 0) return; // 遍历链表中所有被客户端监视的键 listRewind(c->watched_keys,&li); while((ln = listNext(&li))) { list *clients; watchedKey *wk; /* Lookup the watched key -> clients list and remove the client * from the list */ // 从数据库的 watched_keys 字典的 key 键中 // 删除链表里包含的客户端节点 wk = listNodeValue(ln); // 取出客户端链表 clients = dictFetchValue(wk->db->watched_keys, wk->key); redisAssertWithInfo(c, NULL, clients != NULL); // 删除链表中的客户端节点 listDelNode(clients,listSearchKey(clients,c)); /* Kill the entry at all if this was the only client */ // 如果链表已经被清空,那么删除这个键 if (listLength(clients) == 0) dictDelete(wk->db->watched_keys, wk->key); /* Remove this watched key from the client->watched list */ // 从链表中移除 key 节点 listDelNode(c->watched_keys,ln); decrRefCount(wk->key); zfree(wk); } }
static void clientDisconnected(const redisAsyncContext *context, int status) { listNode *ln; client c = (client)context->data; if (status != REDIS_OK) { fprintf(stderr,"Disconnected: %s\n",c->context->errstr); exit(1); } ln = listSearchKey(config.clients,c); assert(ln != NULL); listDelNode(config.clients,ln); zfree(c); /* The run was not done, create new client(s). */ if (!config.done) { createMissingClients(); } /* Stop the event loop when all clients were disconnected */ if (!listLength(config.clients)) { aeStop(config.el); } }