Пример #1
0
/* 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;
}
Пример #2
0
/* 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);
}
Пример #3
0
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;
}
Пример #4
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;
    }
}
Пример #5
0
/* 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;
}
Пример #6
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);
    }
}
Пример #7
0
/* 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);
}
Пример #8
0
/* 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);
}
Пример #9
0
/* 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);
    }
}
Пример #10
0
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;
}
Пример #11
0
//解阻塞一个正在阻塞中的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;
    }
}
Пример #12
0
/*	模式订阅,即设置客户端订阅某模式。如果订阅成功则返回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;
}
Пример #13
0
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;
}
Пример #14
0
// 撤销对这个客户端的所有 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);
    }
}
Пример #15
0
void  freeClient(void *vc) {
    ugClient *c = (ugClient *) vc;
    listNode *node = listSearchKey(server.clients, c);
    if (node) {
        listDelNode(server.clients, node);
    }

}
Пример #16
0
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;
}
Пример #17
0
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);
}
Пример #18
0
/* 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;
}
Пример #20
0
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);
}
Пример #21
0
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);
}
Пример #22
0
/*	退订频道,即取消客户端对某频道的订阅。如果操作成功返回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;
}
Пример #24
0
/* 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;
}
Пример #25
0
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;
}
Пример #26
0
/*
 * 取消所有该客户端监视的 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);
    }
}
Пример #27
0
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;
}
Пример #28
0
/* 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);
    }
}
Пример #30
0
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);
    }
}