Example #1
0
/* Duplicate the whole list. On out of memory NULL is returned.
 * On success a copy of the original list is returned.
 *
 * The 'Dup' method set with listSetDupMethod() function is used
 * to copy the node value. Otherwise the same pointer value of
 * the original node is used as value of the copied node.
 *
 * The original list both on success or error is never modified. */
hilist *listDup(hilist *orig)
{
    hilist *copy;
    listIter *iter;
    listNode *node;

    if ((copy = listCreate()) == NULL)
        return NULL;
    copy->dup = orig->dup;
    copy->free = orig->free;
    copy->match = orig->match;
    iter = listGetIterator(orig, AL_START_HEAD);
    while((node = listNext(iter)) != NULL) {
        void *value;

        if (copy->dup) {
            value = copy->dup(node->value);
            if (value == NULL) {
                listRelease(copy);
                listReleaseIterator(iter);
                return NULL;
            }
        } else
            value = node->value;
        if (listAddNodeTail(copy, value) == NULL) {
            listRelease(copy);
            listReleaseIterator(iter);
            return NULL;
        }
    }
    listReleaseIterator(iter);
    return copy;
}
Example #2
0
/* Duplicate the whole list. On out of memory NULL is returned.
 * On success a copy of the original list is returned.
 *
 * The 'Dup' method set with listSetDupMethod() function is used
 * to copy the node value. Otherwise the same pointer value of
 * the original node is used as value of the copied node.
 *
 * The original list both on success or error is never modified. */
list *listDup(list *orig)
{
    list *copy;
    listIter iter;
    listNode *node;

    if ((copy = listCreate()) == NULL)
        return NULL;
    copy->dup = orig->dup;
    copy->free = orig->free;
    copy->match = orig->match;
    listRewind(orig, &iter);
    while((node = listNext(&iter)) != NULL) {
        void *value;

        if (copy->dup) {
            value = copy->dup(node->value);
            if (value == NULL) {
                listRelease(copy);
                return NULL;
            }
        } else
            value = node->value;
        if (listAddNodeTail(copy, value) == NULL) {
            listRelease(copy);
            return NULL;
        }
    }
    return copy;
}
Example #3
0
void freeFakeClient(struct redisClient *c) {
    sdsfree(c->querybuf);
    listRelease(c->reply);
    listRelease(c->watched_keys);
    freeClientMultiState(c);
    zfree(c);
}
Example #4
0
void cleanup_http_session(cli *c) {
    if (c->http.resp_hdr) {
        listRelease(c->http.resp_hdr); c->http.resp_hdr = NULL;
    }
    if (c->http.req_hdr)  {
        listRelease(c->http.req_hdr);  c->http.req_hdr = NULL;
    }
}
Example #5
0
void vnode_free(vnode_t *vnode){

    work_queue_t *wq = vnode->write_queue;
    if ( wq != NULL ) {
        exit_work_queue(wq);
        zfree(wq);
        vnode->write_queue = NULL;
    }

    if ( vnode->logFile != 0 ){
        close(vnode->logFile);
        vnode->logFile = 0;
    }

    if ( vnode->active_slicedb != NULL ){
        uint32_t active_slicedb_id = vnode->active_slicedb->id;
        for ( int db_id = 0 ; db_id < active_slicedb_id ; db_id++ ){
            if ( vnode->slicedbs[db_id] != NULL ){
                slicedb_free(vnode->slicedbs[db_id]);
                vnode->slicedbs[db_id] = NULL;
            }
        }
    }

    if ( vnode->kvdb_metadata != NULL ){
        kvdb_close(vnode->kvdb_metadata);
        vnode->kvdb_metadata = NULL;
    }

    if ( vnode->caching_objects != NULL ){
        object_queue_free(vnode->caching_objects);
        vnode->caching_objects = NULL;
    }

    listRelease(vnode->received_objects);
    vnode->received_object_size = 0;
    listRelease(vnode->standby_objects);
    vnode->standby_object_size = 0;

    /* Index DB */
    /*if ( vnode->kvdb != NULL ){*/
        /*kvdb_close(vnode->kvdb);*/
        /*vnode->kvdb = NULL;*/
    /*}*/

    /* datazones */
    int i;
    for ( i = 0 ; i < MAX_DATAZONES ; i++ ){
       if ( vnode->datazones[i] != NULL ){
           datazone_destroy(vnode->datazones[i]);
           zfree(vnode->datazones[i]);
       }
    }

    zfree(vnode);
}
Example #6
0
void freeClient(vuiClient *c) {
    listNode *ln;
    listIter *it;
    cJSON *json;

    /* Free the query buffer */
    sdsfree(c->querybuf);
    sdsfree(c->querymsg);
    sdsfree(c->res.body);
    sdsfree(c->res.reason);
    sdsfree(c->res.buf);

    /* 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);
    }
    it = listGetIterator(c->jsons, AL_START_HEAD);

    while((ln = listNext(it)))
    {
        json = (cJSON *)ln->value;
        cJSON_Delete(json);
        listDelNode(c->jsons, ln);
    }
    listRelease(c->jsons);
    listReleaseIterator(it);


    zfree(c);
    server.client = NULL;
}
Example #7
0
void dictCounterDestructor(void *privdata, void *val) {
    DICT_NOTUSED(privdata);
    listNode *ln;
    listIter li;
    counter *cntr = val;
    pubsub *p;

    /* Unsubscribe everyone */
    if (cntr->subscribers != NULL) {
        while (listLength(cntr->subscribers)) {
            ln = listFirst(cntr->subscribers);
            p  = listNodeValue(ln);
            pubsubUnsubscribeCounter(p->c,cntr->name,1);
        }
    }

    /* Free all shards */
    listRewind(cntr->shards,&li);
    while ((ln = listNext(&li)) != NULL) {
        shard *shrd = listNodeValue(ln);
        zfree(shrd);
    }

    listRelease(cntr->shards);
    if (cntr->want_acks) dictRelease(cntr->want_acks);

    /* cntr->name will be freed by the dict code. */

    zfree(cntr);
}
Example #8
0
int luaworkDoDir(lua_State *L,const char *path, char *err) {
    int ret = UGOK;
    sds relpath = sdsempty();
    list *queue = listCreate();
    listNode *node=NULL;
    listIter *iter = NULL;

    if (xfilelistdir(path, "*.lua", queue) == UGERR) {
        luaworkSetError(err, "list files for %s failed", path);
        ret = UGERR;
        goto END;
    }

    iter = listGetIterator(queue, AL_START_HEAD);

    while ((node=listNext(iter))!=NULL) {
        const char *filename = (char *) (node->value);
        sdsclear(relpath);
        relpath = sdscatprintf(relpath, "%s/%s", path, filename);
        ret = luaworkDoFile(L, relpath, err);
        if (ret != UGOK) break;
    }

    listReleaseIterator(iter);
END:
    listRelease(queue);
    sdsfree(relpath);
    return ret;

}
void
msg_put(struct msg *msg)
{
    listNode *node;
    struct mbuf *mbuf;

    log_debug(LOG_VVERB, "put msg %p id %"PRIu64"", msg, msg->id);

    while (listLength(msg->data) > 0) {

        node = listFirst(msg->data);
        mbuf = listNodeValue(node);

        listDelNode(msg->data, node);

        mbuf_put(mbuf);
    }

    listRelease(msg->data);
    msg->data = NULL;

    if (msg->frag_seq) {
        rmt_free(msg->frag_seq);
        msg->frag_seq = NULL;
    }

    if (msg->keys) {
        msg->keys->nelem = 0; /* a hack here */
        array_destroy(msg->keys);
        msg->keys = NULL;
    }

    msg->mb = NULL;
}
Example #10
0
/* This function free the old AOF rewrite buffer if needed, and initialize
 * a fresh new one. It tests for server.aof_rewrite_buf_blocks equal to NULL
 * so can be used for the first initialization as well. */
void aofRewriteBufferReset(void) {
    if (server.aof_rewrite_buf_blocks)
        listRelease(server.aof_rewrite_buf_blocks);

    server.aof_rewrite_buf_blocks = listCreate();
    listSetFreeMethod(server.aof_rewrite_buf_blocks,zfree);
}
Example #11
0
int mgr_on_process_init(event_manager* ev_mgr)
{
    if (ev_mgr->excluded_threads != NULL)
        listRelease(ev_mgr->excluded_threads);
    ev_mgr->excluded_threads = NULL;
    ev_mgr->excluded_threads = listCreate();
    ev_mgr->excluded_threads->match = &pidcomp;

    int rc = launch_rdma(ev_mgr->con_node);
    if (rc != 0 )
        fprintf(stderr, "EVENT MANAGER : Cannot start rdma\n");

    rc = launch_replica_thread(ev_mgr->con_node, ev_mgr->excluded_threads);
    if (rc != 0 )
        fprintf(stderr, "EVENT MANAGER : Cannot launch replica thread\n");

    pthread_t check_point_thread;
    if (pthread_create(&check_point_thread, NULL, &check_point_thread_start, NULL) != 0) 
        fprintf(stderr, "EVENT MANAGER : Cannot create check point thread\n");

    pthread_t *ck_thread = (pthread_t*)malloc(sizeof(pthread_t));
    *ck_thread = check_point_thread;
    listAddNodeTail(ev_mgr->excluded_threads, (void*)ck_thread);

    return rc;
}
Example #12
0
File: aof.c Project: Akuan1994/Mira
void aofRewriteBufferReset(void){
    /*release old buffer list if it exists, create new buffer list*/
    if(server.aof_rewrite_buf_blocks){
        listRelease(server.aof_rewrite_buf_blocks);
    }
    server.aof_rewrite_buf_blocks = listCreate();
    listSetFreeMethod(server.aof_rewrite_buf_blocks, zfree);
}
Example #13
0
list *listDup(list *orign)
/*{{{*/
{
    list *cpy;
    listIter *iter;
    listNode *node;

    if((cpy = listCreate()) == NULL)
    {
        return NULL;
    }

    cpy->free = orign->free;
    cpy->dup = orign->dup;
    cpy->match = orign->match;

    iter = listGetIterator(orign, AL_START_HEAD);
    while((node = listNext(iter)) != NULL)
    {
        void *value;
        if(cpy->dup)
        {
            value = cpy->dup(node->value);
            if(value == NULL)
            {
                listRelease(cpy);
                listReleaseIterator(iter);
                return NULL;
            }
        }
        else
        {
            value = node->value;
        }

        //出错只有一种情况,就是malloc失败了,return NULL;
        if(listAddNodeTail(cpy, value) == NULL)
        {
            listRelease(cpy);
            listReleaseIterator(iter);
            return NULL;
        }
    }
    listReleaseIterator(iter);
    return cpy;
}
Example #14
0
static void freeListOfIndRow(list *ll, int num_cols, bool is_ob) {
    listNode *ln;
    listIter *li = listGetIterator(ll, AL_START_HEAD);
    while((ln = listNext(li)) != NULL) {
        freeIndRow(ln->value, num_cols, is_ob, 1);
    }
    listReleaseIterator(li);
    listRelease(ll);
}
Example #15
0
/* 列表赋值方法,传入的参数为原始列表 */
list *listDup(list *orig)
{
    list *copy;
    listIter *iter;
    listNode *node;

	//如果创建列表失败则直接返回
    if ((copy = listCreate()) == NULL)
        return NULL;
    //为新列表赋值好3个函数指针
    copy->dup = orig->dup;
    copy->free = orig->free;
    copy->match = orig->match;
    //获得从头方向开始的迭代器
    iter = listGetIterator(orig, AL_START_HEAD);
    while((node = listNext(iter)) != NULL) {
    	//从前往后遍历结点
        void *value;

        if (copy->dup) {
        	//如果定义了列表复制方法,则调用dup方法
            value = copy->dup(node->value);
            if (value == NULL) {
            	//如果发生OOM内存溢出问题,直接释放所有空间
                listRelease(copy);
                listReleaseIterator(iter);
                return NULL;
            }
        } else
        	//没定义直接复制函数指针
            value = node->value;
        if (listAddNodeTail(copy, value) == NULL) {
        	//后面的结点都是从尾部逐一添加结点,如果内存溢出,同上操作
            listRelease(copy);
            listReleaseIterator(iter);
            return NULL;
        }
    }
    //最后释放迭代器
    listReleaseIterator(iter);
    return copy;
}
Example #16
0
File: ae.c Project: naver/nbase-arc
void aeDeleteEventLoop(aeEventLoop *eventLoop) {
    aeApiFree(eventLoop);
#ifdef _WIN32
    dictRelease(eventLoop->fdiMap->map);
    listRelease(eventLoop->fdiMap->recycle_pool);
    zfree(eventLoop->fdiMap);
#endif
    zfree(eventLoop->events);
    zfree(eventLoop->fired);
    zfree(eventLoop);
}
Example #17
0
void delete_list()
{
    listNode	*node;
    list	*ll=found_list(&node);
    if(ll){
	listDelNode(listall,node);
	listRelease(ll);
	printf("释放完毕\n");
    }else{
	printf("没有这个链表\n");
    }
}
Example #18
0
void freeListObject(robj *o) {
    switch (o->encoding) {
    case REDIS_ENCODING_LINKEDLIST:
        listRelease((list*) o->ptr);
        break;
    case REDIS_ENCODING_ZIPLIST:
        zfree(o->ptr);
        break;
    default:
        redisPanic("Unknown list encoding type");
    }
}
Example #19
0
static void init_DXDB_PersistentStorageItems(uint32 ntbl, uint32 nindx) {
    if (Tbl) free(Tbl);
    Num_tbls = 0;
    Tbl      = malloc(sizeof(r_tbl_t) * ntbl);
    bzero(Tbl,        sizeof(r_tbl_t) * ntbl);
    Tbl_HW   = ntbl;
    if (TblD) dictRelease(TblD);
    TblD     = dictCreate(&sdsDictType, NULL);
    if (DropT) { listRelease(DropT); DropT = NULL; }

    if (Index) free(Index);
    Num_indx = 0;
    Index    = malloc(sizeof(r_ind_t) * nindx);
    bzero(Index,      sizeof(r_ind_t) * nindx);
    Ind_HW   = nindx;
    if (IndD) dictRelease(IndD);
    IndD     = dictCreate(&sdsDictType, NULL);
    if (DropI) { listRelease(DropI); DropI = NULL; }

    if (StmtD) dictRelease(StmtD);
    StmtD    = dictCreate(&dbDictType,  NULL);
}
Example #20
0
/* Duplicate the whole list. On out of memory NULL is returned.
 * On success a copy of the original list is returned.
 *
 * The 'Dup' method set with listSetDupMethod() function is used
 * to copy the node value. Otherwise the same pointer value of
 * the original node is used as value of the copied node.
 *
 * The original list both on success or error is never modified. */
list *listDup(list *orig)
{
    list *copy;
    listIter *iter;
    listNode *node;

    if ((copy = listCreate()) == NULL)
        return NULL;
    /* set the auxiliary function */
    copy->dup = orig->dup;
    copy->free = orig->free;
    copy->match = orig->match;
    /* get iter of list from head */
    iter = listGetIterator(orig, AL_START_HEAD);
    /* loop all the node of list */
    while((node = listNext(iter)) != NULL) {
        void *value;
        /* if there is a user defined copy function */
        if (copy->dup) {
            /* set value by calling user defined function */
            value = copy->dup(node->value);
            if (value == NULL) { /* opppps, we get some error */
                listRelease(copy);/* release the new list */
                listReleaseIterator(iter); /* release the iterator */
                return NULL;
            }
        } else
            value = node->value; /* shadow copy if there isn't a user defined function */
        if (listAddNodeTail(copy, value) == NULL) {
            /* if we get some error when add the new node to the end of the new list */
            listRelease(copy);/* release the new list */
            listReleaseIterator(iter); /* release the iterator */
            return NULL;
        }
    }
    listReleaseIterator(iter);/* release the iterator */
    return copy;
}
Example #21
0
/* *
 * slotsdel slot1 [slot2 ...]
 * */
void
slotsdelCommand(redisClient *c) {
    int slots_slot[HASH_SLOTS_SIZE];
    int n = 0;
    if (c->argc <= 1) {
        addReplyErrorFormat(c, "wrong number of arguments for 'slotsdel' command");
        return;
    }
    int i;
    for (i = 1; i < c->argc; i ++) {
        int slot;
        if (parse_slot(c, c->argv[i], &slot) != 0) {
            return;
        }
        slots_slot[n] = slot;
        n ++;
    }
    for (i = 0; i < n; i ++) {
        dict *d = c->db->hash_slots[slots_slot[i]];
        int s = dictSize(d);
        if (s == 0) {
            continue;
        }
        list *l = listCreate();
        listSetFreeMethod(l, decrRefCountVoid);
        unsigned long cursor = 0;
        do {
            cursor = dictScan(d, cursor, slotsScanSdsKeyCallback, l);
        } while (cursor != 0);
        while (1) {
            listNode *head = listFirst(l);
            if (head == NULL) {
                break;
            }
            robj *key = listNodeValue(head);
            robj *keys[] = {key};
            slotsremove(c, keys, 1, 0);
            listDelNode(l, head);
        }
        listRelease(l);
    }
    addReplyMultiBulkLen(c, n);
    for (i = 0; i < n; i ++) {
        int n = slots_slot[i];
        int s = dictSize(c->db->hash_slots[n]);
        addReplyMultiBulkLen(c, 2);
        addReplyLongLong(c, n);
        addReplyLongLong(c, s);
    }
}
Example #22
0
static void listDeleteClientObjects(void *cl) {
    ugClient *c = (ugClient *) cl;
    resetClient(c);
    if (c->querybuf) sdsfree(c->querybuf);

    if (c->reply) {
        LOG_TRACE("reply size :%d", listLength(c->reply));
        listRelease(c->reply);
    }

    pubsubUnsubscribeAllChannels(c, 0);
    if (c->pubsub_channels) dictRelease(c->pubsub_channels);
    if (c->pubsub_patterns) listRelease(c->pubsub_patterns);

    aeDeleteFileEvent(server.el, c->fd, AE_READABLE);
    aeDeleteFileEvent(server.el, c->fd, AE_WRITABLE);
#ifdef _WIN32
    aeWinCloseSocket(c->fd);
#else
    close(c->fd);
#endif
    zfree(c);
    c = NULL;
}
Example #23
0
static void free_redis_test_client(redis_test_client *c)
{
	printf("%s %d: fd = %d\n", __FUNCTION__, __LINE__, c->fd);	
    /* Free the query buffer */
    sdsfree(c->querybuf);
    c->querybuf = NULL;
    /* Free data structures. */
    listRelease(c->reply);

    /* Unlink the client: this will close the socket, remove the I/O
     * handlers, and remove references of the client from different
     * places where active clients may be referenced. */
    unlink_redis_test_client(c);
    zfree(c);
}
Example #24
0
File: ae.c Project: naver/nbase-arc
aeEventLoop *aeCreateEventLoop(int setsize) {
    aeEventLoop *eventLoop;
    int i;

    if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err;
    eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize);
    eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize);
    if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err;
    eventLoop->setsize = setsize;
    eventLoop->lastTime = time(NULL);
    eventLoop->timeEventHead = NULL;
    eventLoop->timeEventNextId = 0;
    eventLoop->stop = 0;
    eventLoop->maxfd = EVENTLOOP_MAXFD_INITIAL_VALUE;
    eventLoop->beforesleep = NULL;
    if (aeApiCreate(eventLoop) == -1) goto err;
    /* Events with mask == AE_NONE are not set. So let's initialize the
     * vector with it. */
    for (i = 0; i < setsize; i++)
        eventLoop->events[i].mask = AE_NONE;
#ifdef _WIN32
    if ((eventLoop->fdiMap = zmalloc(sizeof(fd_index_map_t))) == NULL) goto err;
    eventLoop->fdiMap->map = dictCreate(&fdiDictType, NULL);
    eventLoop->fdiMap->recycle_pool = listCreate();
    if (eventLoop->fdiMap->map == NULL || eventLoop->fdiMap->recycle_pool == NULL) goto err;
    eventLoop->fdiMap->next_available = 3;	// stdin(0), stdout(1) and stderr(2)
#endif
    return eventLoop;

err:
#ifdef _WIN32
    if (eventLoop->fdiMap) {
        if (eventLoop->fdiMap->map != NULL) dictRelease(eventLoop->fdiMap->map);
        if (eventLoop->fdiMap->recycle_pool != NULL) listRelease(eventLoop->fdiMap->recycle_pool);
        zfree(eventLoop->fdiMap);
    }
#endif
    if (eventLoop) {
        zfree(eventLoop->events);
        zfree(eventLoop->fired);
        zfree(eventLoop);
    }
    return NULL;
}
Example #25
0
void lsCommand(redisClient* c)
{
    DIR* pstDir = opendir((const char*)c->argv[1]->ptr);
    if (pstDir == NULL) {
        addReplyErrorFormat(c, "opendir fail, %s", strerror(errno));
        return;
    }

    list* dir = listCreate();
    struct dirent* pstDirent = NULL;
    while ((pstDirent = readdir(pstDir)) != NULL) {

        if(strcmp(pstDirent->d_name, ".") == 0 ||
            strcmp(pstDirent->d_name, "..") == 0)
            continue;

        sds path = sdsdup(c->argv[1]->ptr);
        size_t len = sdslen(path);
        if (path[len - 1] != '/')
            path = sdscat(path, "/");

        path = sdscat(path, pstDirent->d_name);
        listAddNodeTail(dir, path);
    }
    closedir(pstDir);

    addReplyMultiBulkLen(c, listLength(dir));
    listIter* iter = listGetIterator(dir, AL_START_HEAD);
    listNode* node = NULL;
    while ((node = listNext(iter))) {
        addReplyBulkCString(c, node->value);
        sdsfree(node->value);
        listDelNode(dir, node);
    }
    listRelease(dir);
}
Example #26
0
void aio_destroy(void)
{
    if (aio_ctx)
    {
        if (-1 == io_destroy(aio_ctx))
        {
            logerror("io_destroy fail. %s", strerror(errno));
        }
    }
    if (aio_fd)
    {
        if (-1 == close(aio_fd))
        {
            logerror("close eventfd fail. %s", strerror(errno));
        }

    }
#if  AIO_QUEUE
    if (aio_queue)
    {
        listRelease(aio_queue);
    }
#endif
}
Example #27
0
int 
main(int argc, char *argv[])
{
    unsigned char *zl, *p;
    unsigned char *entry;
    unsigned int elen;
    long long value;

    /* If an argument is given, use it as the random seed. */
    if (argc == 2)
        srand(atoi(argv[1]));

    zl = createIntList();
    ziplistRepr(zl);

    zl = createList();
    ziplistRepr(zl);

    pop(zl,ZIPLIST_TAIL);
    ziplistRepr(zl);

    pop(zl,ZIPLIST_HEAD);
    ziplistRepr(zl);

    pop(zl,ZIPLIST_TAIL);
    ziplistRepr(zl);

    pop(zl,ZIPLIST_TAIL);
    ziplistRepr(zl);

    printf("Get element at index 3:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 3);
        if (!ziplistGet(p, &entry, &elen, &value)) {
            printf("ERROR: Could not access index 3\n");
            return 1;
        }
        if (entry) {
            if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            printf("\n");
        } else {
            printf("%lld\n", value);
        }
        printf("\n");
    }

    printf("Get element at index 4 (out of range):\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 4);
        if (p == NULL) {
            printf("No entry\n");
        } else {
            printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl);
            return 1;
        }
        printf("\n");
    }

    printf("Get element at index -1 (last element):\n");
    {
        zl = createList();
        p = ziplistIndex(zl, -1);
        if (!ziplistGet(p, &entry, &elen, &value)) {
            printf("ERROR: Could not access index -1\n");
            return 1;
        }
        if (entry) {
            if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            printf("\n");
        } else {
            printf("%lld\n", value);
        }
        printf("\n");
    }

    printf("Get element at index -4 (first element):\n");
    {
        zl = createList();
        p = ziplistIndex(zl, -4);
        if (!ziplistGet(p, &entry, &elen, &value)) {
            printf("ERROR: Could not access index -4\n");
            return 1;
        }
        if (entry) {
            if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            printf("\n");
        } else {
            printf("%lld\n", value);
        }
        printf("\n");
    }

    printf("Get element at index -5 (reverse out of range):\n");
    {
        zl = createList();
        p = ziplistIndex(zl, -5);
        if (p == NULL) {
            printf("No entry\n");
        } else {
            printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", p-zl);
            return 1;
        }
        printf("\n");
    }

    printf("Iterate list from 0 to end:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 0);
        while (ziplistGet(p, &entry, &elen, &value)) {
            printf("Entry: ");
            if (entry) {
                if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            } else {
                printf("%lld", value);
            }
            p = ziplistNext(zl,p);
            printf("\n");
        }
        printf("\n");
    }

    printf("Iterate list from 1 to end:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 1);
        while (ziplistGet(p, &entry, &elen, &value)) {
            printf("Entry: ");
            if (entry) {
                if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            } else {
                printf("%lld", value);
            }
            p = ziplistNext(zl,p);
            printf("\n");
        }
        printf("\n");
    }

    printf("Iterate list from 2 to end:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 2);
        while (ziplistGet(p, &entry, &elen, &value)) {
            printf("Entry: ");
            if (entry) {
                if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            } else {
                printf("%lld", value);
            }
            p = ziplistNext(zl,p);
            printf("\n");
        }
        printf("\n");
    }

    printf("Iterate starting out of range:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, 4);
        if (!ziplistGet(p, &entry, &elen, &value)) {
            printf("No entry\n");
        } else {
            printf("ERROR\n");
        }
        printf("\n");
    }

    printf("Iterate from back to front:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, -1);
        while (ziplistGet(p, &entry, &elen, &value)) {
            printf("Entry: ");
            if (entry) {
                if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            } else {
                printf("%lld", value);
            }
            p = ziplistPrev(zl,p);
            printf("\n");
        }
        printf("\n");
    }

    printf("Iterate from back to front, deleting all items:\n");
    {
        zl = createList();
        p = ziplistIndex(zl, -1);
        while (ziplistGet(p, &entry, &elen, &value)) {
            printf("Entry: ");
            if (entry) {
                if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
            } else {
                printf("%lld", value);
            }
            zl = ziplistDelete(zl,&p);
            p = ziplistPrev(zl,p);
            printf("\n");
        }
        printf("\n");
    }

    printf("Delete inclusive range 0,0:\n");
    {
        zl = createList();
        zl = ziplistDeleteRange(zl, 0, 1);
        ziplistRepr(zl);
    }

    printf("Delete inclusive range 0,1:\n");
    {
        zl = createList();
        zl = ziplistDeleteRange(zl, 0, 2);
        ziplistRepr(zl);
    }

    printf("Delete inclusive range 1,2:\n");
    {
        zl = createList();
        zl = ziplistDeleteRange(zl, 1, 2);
        ziplistRepr(zl);
    }

    printf("Delete with start index out of range:\n");
    {
        zl = createList();
        zl = ziplistDeleteRange(zl, 5, 1);
        ziplistRepr(zl);
    }

    printf("Delete with num overflow:\n");
    {
        zl = createList();
        zl = ziplistDeleteRange(zl, 1, 5);
        ziplistRepr(zl);
    }

    printf("Delete foo while iterating:\n");
    {
        zl = createList();
        p = ziplistIndex(zl,0);
        while (ziplistGet(p,&entry,&elen,&value)) {
            if (entry && strncmp("foo",(char*)entry,elen) == 0) {
                printf("Delete foo\n");
                zl = ziplistDelete(zl,&p);
            } else {
                printf("Entry: ");
                if (entry) {
                    if (elen && fwrite(entry,elen,1,stdout) == 0)
                        perror("fwrite");
                } else {
                    printf("%lld",value);
                }
                p = ziplistNext(zl,p);
                printf("\n");
            }
        }
        printf("\n");
        ziplistRepr(zl);
    }

    printf("Regression test for >255 byte strings:\n");
    {
        char v1[257],v2[257];
        memset(v1,'x',256);
        memset(v2,'y',256);
        zl = ziplistNew();
        zl = ziplistPush(zl,(unsigned char*)v1,strlen(v1),ZIPLIST_TAIL);
        zl = ziplistPush(zl,(unsigned char*)v2,strlen(v2),ZIPLIST_TAIL);

        /* Pop values again and compare their value. */
        p = ziplistIndex(zl,0);
        assert(ziplistGet(p,&entry,&elen,&value));
        assert(strncmp(v1,(char*)entry,elen) == 0);
        p = ziplistIndex(zl,1);
        assert(ziplistGet(p,&entry,&elen,&value));
        assert(strncmp(v2,(char*)entry,elen) == 0);
        printf("SUCCESS\n\n");
    }

    printf("Regression test deleting next to last entries:\n");
    {
        char v[3][257];
        zlentry e[3];
        int i;

        for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) {
            memset(v[i], 'a' + i, sizeof(v[0]));
        }

        v[0][256] = '\0';
        v[1][  1] = '\0';
        v[2][256] = '\0';

        zl = ziplistNew();
        for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) {
            zl = ziplistPush(zl, (unsigned char *) v[i], strlen(v[i]), ZIPLIST_TAIL);
        }

        verify(zl, e);

        assert(e[0].prevrawlensize == 1);
        assert(e[1].prevrawlensize == 5);
        assert(e[2].prevrawlensize == 1);

        /* Deleting entry 1 will increase `prevrawlensize` for entry 2 */
        unsigned char *p = e[1].p;
        zl = ziplistDelete(zl, &p);

        verify(zl, e);

        assert(e[0].prevrawlensize == 1);
        assert(e[1].prevrawlensize == 5);

        printf("SUCCESS\n\n");
    }

    printf("Create long list and check indices:\n");
    {
        zl = ziplistNew();
        char buf[32];
        int i,len;
        for (i = 0; i < 1000; i++) {
            len = sprintf(buf,"%d",i);
            zl = ziplistPush(zl,(unsigned char*)buf,len,ZIPLIST_TAIL);
        }
        for (i = 0; i < 1000; i++) {
            p = ziplistIndex(zl,i);
            assert(ziplistGet(p,NULL,NULL,&value));
            assert(i == value);

            p = ziplistIndex(zl,-i-1);
            assert(ziplistGet(p,NULL,NULL,&value));
            assert(999-i == value);
        }
        printf("SUCCESS\n\n");
    }

    printf("Compare strings with ziplist entries:\n");
    {
        zl = createList();
        p = ziplistIndex(zl,0);
        if (!ziplistCompare(p,(unsigned char*)"hello",5)) {
            printf("ERROR: not \"hello\"\n");
            return 1;
        }
        if (ziplistCompare(p,(unsigned char*)"hella",5)) {
            printf("ERROR: \"hella\"\n");
            return 1;
        }

        p = ziplistIndex(zl,3);
        if (!ziplistCompare(p,(unsigned char*)"1024",4)) {
            printf("ERROR: not \"1024\"\n");
            return 1;
        }
        if (ziplistCompare(p,(unsigned char*)"1025",4)) {
            printf("ERROR: \"1025\"\n");
            return 1;
        }
        printf("SUCCESS\n\n");
    }

    printf("Stress with random payloads of different encoding:\n");
    {
        int i,j,len,where;
        unsigned char *p;
        char buf[1024];
        int buflen;
        list *ref;
        listNode *refnode;

        /* Hold temp vars from ziplist */
        unsigned char *sstr;
        unsigned int slen;
        long long sval;

        for (i = 0; i < 20000; i++) {
            zl = ziplistNew();
            ref = listCreate();
            listSetFreeMethod(ref, sdsfree);
            len = rand() % 256;

            /* Create lists */
            for (j = 0; j < len; j++) {
                where = (rand() & 1) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
                if (rand() % 2) {
                    buflen = randstring(buf,1,sizeof(buf)-1);
                } else {
                    switch(rand() % 3) {
                    case 0:
                        buflen = sprintf(buf,"%lld",(0LL + rand()) >> 20);
                        break;
                    case 1:
                        buflen = sprintf(buf,"%lld",(0LL + rand()));
                        break;
                    case 2:
                        buflen = sprintf(buf,"%lld",(0LL + rand()) << 20);
                        break;
                    default:
                        assert(NULL);
                    }
                }

                /* Add to ziplist */
                zl = ziplistPush(zl, (unsigned char*)buf, buflen, where);

                /* Add to reference list */
                if (where == ZIPLIST_HEAD) {
                    listAddNodeHead(ref,sdsnewlen(buf, buflen));
                } else if (where == ZIPLIST_TAIL) {
                    listAddNodeTail(ref,sdsnewlen(buf, buflen));
                } else {
                    assert(NULL);
                }
            }

            assert(listLength(ref) == ziplistLen(zl));
            for (j = 0; j < len; j++) {
                /* Naive way to get elements, but similar to the stresser
                 * executed from the Tcl test suite. */
                p = ziplistIndex(zl,j);
                refnode = listIndex(ref,j);

                assert(ziplistGet(p,&sstr,&slen,&sval));
                if (sstr == NULL) {
                    buflen = sprintf(buf,"%lld",sval);
                } else {
                    buflen = slen;
                    memcpy(buf,sstr,buflen);
                    buf[buflen] = '\0';
                }
                assert(memcmp(buf,listNodeValue(refnode),buflen) == 0);
            }
            zfree(zl);
            listRelease(ref);
        }
        printf("SUCCESS\n\n");
    }

    printf("Stress with variable ziplist size:\n");
    {
        stress(ZIPLIST_HEAD,100000,16384,256);
        stress(ZIPLIST_TAIL,100000,16384,256);
    }

    return 0;
}
Example #28
0
/* The SORT command is the most complex command in Redis. Warning: this code
 * is optimized for speed and a bit less for readability */
void sortCommand(redisClient *c) {
    list *operations;
    unsigned int outputlen = 0;
    int desc = 0, alpha = 0;
    long limit_start = 0, limit_count = -1, start, end;
    int j, dontsort = 0, vectorlen;
    int getop = 0; /* GET operation counter */
    int int_convertion_error = 0;
    robj *sortval, *sortby = NULL, *storekey = NULL;
    redisSortObject *vector; /* Resulting vector to sort */

    /* Lookup the key to sort. It must be of the right types */
    sortval = lookupKeyRead(c->db,c->argv[1]);
    if (sortval && sortval->type != REDIS_SET && sortval->type != REDIS_LIST &&
        sortval->type != REDIS_ZSET)
    {
        addReply(c,shared.wrongtypeerr);
        return;
    }

    /* Create a list of operations to perform for every sorted element.
     * Operations can be GET/DEL/INCR/DECR */
    operations = listCreate();
    listSetFreeMethod(operations,zfree);
    j = 2;

    /* Now we need to protect sortval incrementing its count, in the future
     * SORT may have options able to overwrite/delete keys during the sorting
     * and the sorted key itself may get destroied */
    if (sortval)
        incrRefCount(sortval);
    else
        sortval = createListObject();

    /* The SORT command has an SQL-alike syntax, parse it */
    while(j < c->argc) {
        int leftargs = c->argc-j-1;
        if (!strcasecmp(c->argv[j]->ptr,"asc")) {
            desc = 0;
        } else if (!strcasecmp(c->argv[j]->ptr,"desc")) {
            desc = 1;
        } else if (!strcasecmp(c->argv[j]->ptr,"alpha")) {
            alpha = 1;
        } else if (!strcasecmp(c->argv[j]->ptr,"limit") && leftargs >= 2) {
            if ((getLongFromObjectOrReply(c, c->argv[j+1], &limit_start, NULL) != REDIS_OK) ||
                (getLongFromObjectOrReply(c, c->argv[j+2], &limit_count, NULL) != REDIS_OK)) return;
            j+=2;
        } else if (!strcasecmp(c->argv[j]->ptr,"store") && leftargs >= 1) {
            storekey = c->argv[j+1];
            j++;
        } else if (!strcasecmp(c->argv[j]->ptr,"by") && leftargs >= 1) {
            sortby = c->argv[j+1];
            /* If the BY pattern does not contain '*', i.e. it is constant,
             * we don't need to sort nor to lookup the weight keys. */
            if (strchr(c->argv[j+1]->ptr,'*') == NULL) dontsort = 1;
            j++;
        } else if (!strcasecmp(c->argv[j]->ptr,"get") && leftargs >= 1) {
            listAddNodeTail(operations,createSortOperation(
                REDIS_SORT_GET,c->argv[j+1]));
            getop++;
            j++;
        } else {
            decrRefCount(sortval);
            listRelease(operations);
            addReply(c,shared.syntaxerr);
            return;
        }
        j++;
    }

    /* If we have STORE we need to force sorting for deterministic output
     * and replication. We use alpha sorting since this is guaranteed to
     * work with any input. */
    if (storekey && dontsort) {
        dontsort = 0;
        alpha = 1;
        sortby = NULL;
    }

    /* Destructively convert encoded sorted sets for SORT. */
    if (sortval->type == REDIS_ZSET)
        zsetConvert(sortval, REDIS_ENCODING_SKIPLIST);

    /* Load the sorting vector with all the objects to sort */
    switch(sortval->type) {
    case REDIS_LIST: vectorlen = listTypeLength(sortval); break;
    case REDIS_SET: vectorlen =  setTypeSize(sortval); break;
    case REDIS_ZSET: vectorlen = dictSize(((zset*)sortval->ptr)->dict); break;
    default: vectorlen = 0; redisPanic("Bad SORT type"); /* Avoid GCC warning */
    }
    vector = zmalloc(sizeof(redisSortObject)*vectorlen);
    j = 0;

    if (sortval->type == REDIS_LIST) {
        listTypeIterator *li = listTypeInitIterator(sortval,0,REDIS_TAIL);
        listTypeEntry entry;
        while(listTypeNext(li,&entry)) {
            vector[j].obj = listTypeGet(&entry);
            vector[j].u.score = 0;
            vector[j].u.cmpobj = NULL;
            j++;
        }
        listTypeReleaseIterator(li);
    } else if (sortval->type == REDIS_SET) {
        setTypeIterator *si = setTypeInitIterator(sortval);
        robj *ele;
        while((ele = setTypeNextObject(si)) != NULL) {
            vector[j].obj = ele;
            vector[j].u.score = 0;
            vector[j].u.cmpobj = NULL;
            j++;
        }
        setTypeReleaseIterator(si);
    } else if (sortval->type == REDIS_ZSET) {
        dict *set = ((zset*)sortval->ptr)->dict;
        dictIterator *di;
        dictEntry *setele;
        di = dictGetIterator(set);
        while((setele = dictNext(di)) != NULL) {
            vector[j].obj = dictGetKey(setele);
            vector[j].u.score = 0;
            vector[j].u.cmpobj = NULL;
            j++;
        }
        dictReleaseIterator(di);
    } else {
        redisPanic("Unknown type");
    }
    redisAssertWithInfo(c,sortval,j == vectorlen);

    /* Now it's time to load the right scores in the sorting vector */
    if (dontsort == 0) {
        for (j = 0; j < vectorlen; j++) {
            robj *byval;
            if (sortby) {
                /* lookup value to sort by */
                byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
                if (!byval) continue;
            } else {
                /* use object itself to sort by */
                byval = vector[j].obj;
            }

            if (alpha) {
                if (sortby) vector[j].u.cmpobj = getDecodedObject(byval);
            } else {
                if (byval->encoding == REDIS_ENCODING_RAW) {
                    char *eptr;

                    vector[j].u.score = strtod(byval->ptr,&eptr);
                    if (eptr[0] != '\0' || errno == ERANGE ||
                        isnan(vector[j].u.score))
                    {
                        int_convertion_error = 1;
                    }
                } else if (byval->encoding == REDIS_ENCODING_INT) {
                    /* Don't need to decode the object if it's
                     * integer-encoded (the only encoding supported) so
                     * far. We can just cast it */
                    vector[j].u.score = (long)byval->ptr;
                } else {
                    redisAssertWithInfo(c,sortval,1 != 1);
                }
            }

            /* when the object was retrieved using lookupKeyByPattern,
             * its refcount needs to be decreased. */
            if (sortby) {
                decrRefCount(byval);
            }
        }
    }

    /* We are ready to sort the vector... perform a bit of sanity check
     * on the LIMIT option too. We'll use a partial version of quicksort. */
    start = (limit_start < 0) ? 0 : limit_start;
    end = (limit_count < 0) ? vectorlen-1 : start+limit_count-1;
    if (start >= vectorlen) {
        start = vectorlen-1;
        end = vectorlen-2;
    }
    if (end >= vectorlen) end = vectorlen-1;

    server.sort_dontsort = dontsort;
    if (dontsort == 0) {
        server.sort_desc = desc;
        server.sort_alpha = alpha;
        server.sort_bypattern = sortby ? 1 : 0;
        if (sortby && (start != 0 || end != vectorlen-1))
            pqsort(vector,vectorlen,sizeof(redisSortObject),sortCompare, start,end);
        else
            qsort(vector,vectorlen,sizeof(redisSortObject),sortCompare);
    }

    /* Send command output to the output buffer, performing the specified
     * GET/DEL/INCR/DECR operations if any. */
    outputlen = getop ? getop*(end-start+1) : end-start+1;
    if (int_convertion_error) {
        addReplyError(c,"One or more scores can't be converted into double");
    } else if (storekey == NULL) {
        /* STORE option not specified, sent the sorting result to client */
        addReplyMultiBulkLen(c,outputlen);
        for (j = start; j <= end; j++) {
            listNode *ln;
            listIter li;

            if (!getop) addReplyBulk(c,vector[j].obj);
            listRewind(operations,&li);
            while((ln = listNext(&li))) {
                redisSortOperation *sop = ln->value;
                robj *val = lookupKeyByPattern(c->db,sop->pattern,
                    vector[j].obj);

                if (sop->type == REDIS_SORT_GET) {
                    if (!val) {
                        addReply(c,shared.nullbulk);
                    } else {
                        addReplyBulk(c,val);
                        decrRefCount(val);
                    }
                } else {
                    /* Always fails */
                    redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET);
                }
            }
        }
    } else {
        robj *sobj = createZiplistObject();

        /* STORE option specified, set the sorting result as a List object */
        for (j = start; j <= end; j++) {
            listNode *ln;
            listIter li;

            if (!getop) {
                listTypePush(sobj,vector[j].obj,REDIS_TAIL);
            } else {
                listRewind(operations,&li);
                while((ln = listNext(&li))) {
                    redisSortOperation *sop = ln->value;
                    robj *val = lookupKeyByPattern(c->db,sop->pattern,
                        vector[j].obj);

                    if (sop->type == REDIS_SORT_GET) {
                        if (!val) val = createStringObject("",0);

                        /* listTypePush does an incrRefCount, so we should take care
                         * care of the incremented refcount caused by either
                         * lookupKeyByPattern or createStringObject("",0) */
                        listTypePush(sobj,val,REDIS_TAIL);
                        decrRefCount(val);
                    } else {
                        /* Always fails */
                        redisAssertWithInfo(c,sortval,sop->type == REDIS_SORT_GET);
                    }
                }
            }
        }
        if (outputlen) {
            setKey(c->db,storekey,sobj);
            server.dirty += outputlen;
        } else if (dbDelete(c->db,storekey)) {
            signalModifiedKey(c->db,storekey);
            server.dirty++;
        }
        decrRefCount(sobj);
        addReplyLongLong(c,outputlen);
    }

    /* Cleanup */
    if (sortval->type == REDIS_LIST || sortval->type == REDIS_SET)
        for (j = 0; j < vectorlen; j++)
            decrRefCount(vector[j].obj);
    decrRefCount(sortval);
    listRelease(operations);
    for (j = 0; j < vectorlen; j++) {
        if (alpha && vector[j].u.cmpobj)
            decrRefCount(vector[j].u.cmpobj);
    }
    zfree(vector);
}
Example #29
0
void syncCommand(redisClient *c) {
    /* ignore SYNC if aleady slave or in monitor mode */
    if (c->flags & REDIS_SLAVE) return;

    /* Refuse SYNC requests if we are a slave but the link with our master
     * is not ok... */
    if (server.masterhost && server.replstate != REDIS_REPL_CONNECTED) {
        addReplyError(c,"Can't SYNC while not connected with my master");
        return;
    }

    /* SYNC can't be issued when the server has pending data to send to
     * the client about already issued commands. We need a fresh reply
     * buffer registering the differences between the BGSAVE and the current
     * dataset, so that we can copy to other slaves if needed. */
    if (listLength(c->reply) != 0) {
        addReplyError(c,"SYNC is invalid with pending input");
        return;
    }

    redisLog(REDIS_NOTICE,"Slave ask for synchronization");
    /* Here we need to check if there is a background saving operation
     * in progress, or if it is required to start one */
    if (server.bgsavechildpid != -1) {
        /* Ok a background save is in progress. Let's check if it is a good
         * one for replication, i.e. if there is another slave that is
         * registering differences since the server forked to save */
        redisClient *slave;
        listNode *ln;
        listIter li;

        listRewind(server.slaves,&li);
        while((ln = listNext(&li))) {
            slave = ln->value;
            if (slave->replstate == REDIS_REPL_WAIT_BGSAVE_END) break;
        }
        if (ln) {
            /* Perfect, the server is already registering differences for
             * another slave. Set the right state, and copy the buffer. */
            listRelease(c->reply);
            c->reply = listDup(slave->reply);
            c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
            redisLog(REDIS_NOTICE,"Waiting for end of BGSAVE for SYNC");
        } else {
            /* No way, we need to wait for the next BGSAVE in order to
             * register differences */
            c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
            redisLog(REDIS_NOTICE,"Waiting for next BGSAVE for SYNC");
        }
    } else {
        /* Ok we don't have a BGSAVE in progress, let's start one */
        redisLog(REDIS_NOTICE,"Starting BGSAVE for SYNC");
        if (rdbSaveBackground(server.dbfilename) != REDIS_OK) {
            redisLog(REDIS_NOTICE,"Replication failed, can't BGSAVE");
            addReplyError(c,"Unable to perform background save");
            return;
        }
        c->replstate = REDIS_REPL_WAIT_BGSAVE_END;
    }
    c->repldbfd = -1;
    c->flags |= REDIS_SLAVE;
    c->slaveseldb = 0;
    listAddNodeTail(server.slaves,c);
    return;
}
Example #30
0
void freeClient(redisClient *c) {
    listNode *ln;

    /* Note that if the client we are freeing is blocked into a blocking
     * call, we have to set querybuf to NULL *before* to call
     * unblockClientWaitingData() to avoid processInputBuffer() will get
     * called. Also it is important to remove the file events after
     * this, because this call adds the READABLE event. */
    sdsfree(c->querybuf);
    c->querybuf = NULL;
    if (c->flags & REDIS_BLOCKED)
        unblockClientWaitingData(c);

    /* UNWATCH all the keys */
    unwatchAllKeys(c);
    listRelease(c->watched_keys);
    /* Unsubscribe from all the pubsub channels */
    pubsubUnsubscribeAllChannels(c,0);
    pubsubUnsubscribeAllPatterns(c,0);
    dictRelease(c->pubsub_channels);
    listRelease(c->pubsub_patterns);
    /* Obvious cleanup */
    aeDeleteFileEvent(server.el,c->fd,AE_READABLE);
    aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);
    listRelease(c->reply);
    freeClientArgv(c);
    close(c->fd);
    /* Remove from the list of clients */
    ln = listSearchKey(server.clients,c);
    redisAssert(ln != NULL);
    listDelNode(server.clients,ln);
    /* Remove from the list of clients waiting for swapped keys, or ready
     * to be restarted, but not yet woken up again. */
    if (c->flags & REDIS_IO_WAIT) {
        redisAssert(server.vm_enabled);
        if (listLength(c->io_keys) == 0) {
            ln = listSearchKey(server.io_ready_clients,c);

            /* When this client is waiting to be woken up (REDIS_IO_WAIT),
             * it should be present in the list io_ready_clients */
            redisAssert(ln != NULL);
            listDelNode(server.io_ready_clients,ln);
        } else {
            while (listLength(c->io_keys)) {
                ln = listFirst(c->io_keys);
                dontWaitForSwappedKey(c,ln->value);
            }
        }
        server.vm_blocked_clients--;
    }
    listRelease(c->io_keys);
    /* Master/slave cleanup.
     * Case 1: we lost the connection with a slave. */
    if (c->flags & REDIS_SLAVE) {
        if (c->replstate == REDIS_REPL_SEND_BULK && c->repldbfd != -1)
            close(c->repldbfd);
        list *l = (c->flags & REDIS_MONITOR) ? server.monitors : server.slaves;
        ln = listSearchKey(l,c);
        redisAssert(ln != NULL);
        listDelNode(l,ln);
    }

    /* Case 2: we lost the connection with the master. */
    if (c->flags & REDIS_MASTER) {
        server.master = NULL;
        server.replstate = REDIS_REPL_CONNECT;
        /* Since we lost the connection with the master, we should also
         * close the connection with all our slaves if we have any, so
         * when we'll resync with the master the other slaves will sync again
         * with us as well. Note that also when the slave is not connected
         * to the master it will keep refusing connections by other slaves. */
        while (listLength(server.slaves)) {
            ln = listFirst(server.slaves);
            freeClient((redisClient*)ln->value);
        }
    }
    /* Release memory */
    zfree(c->argv);
    zfree(c->mbargv);
    freeClientMultiState(c);
    zfree(c);
}