コード例 #1
0
ファイル: async.c プロジェクト: BeyongSpringWater/redis
/* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) {
    redisContext *c = &(ac->c);
    redisCallback cb;
    dictIterator *it;
    dictEntry *de;

    /* Execute pending callbacks with NULL reply. */
    while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK)
        __redisRunCallback(ac,&cb,NULL);

    /* Execute callbacks for invalid commands */
    while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
        __redisRunCallback(ac,&cb,NULL);

    /* Run subscription callbacks callbacks with NULL reply */
    it = dictGetIterator(ac->sub.channels);
    while ((de = dictNext(it)) != NULL)
        __redisRunCallback(ac,dictGetEntryVal(de),NULL);
    dictReleaseIterator(it);
    dictRelease(ac->sub.channels);

    it = dictGetIterator(ac->sub.patterns);
    while ((de = dictNext(it)) != NULL)
        __redisRunCallback(ac,dictGetEntryVal(de),NULL);
    dictReleaseIterator(it);
    dictRelease(ac->sub.patterns);

    /* Signal event lib to clean up */
    _EL_CLEANUP(ac);

    /* Execute disconnect callback. When redisAsyncFree() initiated destroying
     * this context, the status will always be REDIS_OK. */
    if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
        if (c->flags & REDIS_FREEING) {
            ac->onDisconnect(ac,REDIS_OK);
        } else {
            ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
        }
    }

    /* Cleanup self */
    redisFree(c);
}
コード例 #2
0
ファイル: db.c プロジェクト: Elbandi/redis
void movekeysCommand(redisClient *c) {
    redisDb *src, *dst;
    int srcid;

    dictIterator *di;
    dictEntry *de;
    sds pattern = c->argv[1]->ptr;
    int plen = sdslen(pattern), allkeys;
    unsigned long numkeys = 0;

    /* Obtain source and target DB pointers */
    src = c->db;
    srcid = c->db->id;
    if (selectDb(c,atoi(c->argv[2]->ptr)) == REDIS_ERR) {
        addReply(c,shared.outofrangeerr);
        return;
    }
    dst = c->db;
    selectDb(c,srcid); /* Back to the source DB */

    /* If the user is moving using as target the same
     * DB as the source DB it is probably an error. */
    if (src == dst) {
        addReply(c,shared.sameobjecterr);
        return;
    }

    di = dictGetIterator(c->db->dict);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetEntryKey(de);
        robj *keyobj;

        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
            keyobj = createStringObject(key,sdslen(key));
            if (expireIfNeeded(c->db,keyobj) == 0) {
                robj *val = dictGetEntryVal(de);

                /* Try to add the element to the target DB */
                if (dbAdd(dst,keyobj,val) != REDIS_ERR) {
                    incrRefCount(val);

                    /* OK! key moved, free the entry in the source DB */
                    dbDelete(src,keyobj);
                    server.dirty++;
                    numkeys++;
                }
            }
            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);
    addReplyLongLong(c,numkeys);
}
コード例 #3
0
ファイル: t_set.c プロジェクト: jrun/redis
/* Move to the next entry in the set. Returns the object at the current
 * position.
 *
 * Since set elements can be internally be stored as redis objects or
 * simple arrays of integers, setTypeNext returns the encoding of the
 * set object you are iterating, and will populate the appropriate pointer
 * (eobj) or (llobj) accordingly.
 *
 * When there are no longer elements -1 is returned.
 * Returned objects ref count is not incremented, so this function is
 * copy on write friendly. */
int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele) {
    if (si->encoding == REDIS_ENCODING_HT) {
        dictEntry *de = dictNext(si->di);
        if (de == NULL) return -1;
        *objele = dictGetEntryKey(de);
    } else if (si->encoding == REDIS_ENCODING_INTSET) {
        if (!intsetGet(si->subject->ptr,si->ii++,llele))
            return -1;
    }
    return si->encoding;
}
コード例 #4
0
static bool buildJRowReply(build_jrow_reply_t  *b,
                           int                  lvl,
                           robj                *rset[MAX_JOIN_INDXS]) {
    dictIterator *iter;
    dictEntry    *rde = dictFind(rset[lvl]->ptr, b->jk);
    if (rde) {
        robj *setobj = dictGetEntryVal(rde);
        iter         = dictGetIterator(setobj->ptr);
    } else { // this table does not have this column
        if (b->j.obt == Index[server.dbid][b->j_indxs[lvl]].table) {
            Order_by_col_val = NULL;
        }
        for (int j = 0; j < b->j.jind_ncols[lvl]; j++) {
            Rcols[lvl][j]   = &EMPTY_STRING;
            Rc_lens[lvl][j] = 0;
        }
        if (lvl + 1 < b->n_ind) {
            if(!buildJRowReply(b, lvl + 1, rset)) return 0;
        } else {
            if (!jRowReply(&(b->j), lvl)) return 0;
            *b->card = *b->card + 1;
        }
        return 1;
    }

    dictEntry *sde;
    while ((sde = dictNext(iter)) != NULL) {
        char *first_entry;
        robj *item = sde->key;
        if (b->j.obt == Index[server.dbid][b->j_indxs[lvl]].table) {
            obsl_t *ob       = (obsl_t *)item->ptr;
            Order_by_col_val = ob->keys[0];
            first_entry      = (char *)ob->row;
        } else {
            first_entry      = (char *)item->ptr;
        }
        for (int j = 0; j < b->j.jind_ncols[lvl]; j++) {
            Rcols[lvl][j]  = (char **)first_entry;
            first_entry        += PTR_SIZE;
            memcpy(&(Rc_lens[lvl][j]), first_entry, UINT_SIZE);
            first_entry        += UINT_SIZE;
        }
        if (lvl + 1 < b->n_ind) {
            if(!buildJRowReply(b, lvl + 1, rset)) return 0;
        } else {
            if (!jRowReply(&(b->j), lvl)) return 0;
            *b->card = *b->card + 1;
        }
    }
    dictReleaseIterator(iter);
    return 1;
}
コード例 #5
0
ファイル: register.c プロジェクト: cinience/saker
void  destroyTaskMap(dict* p) 
{
    if (p) {
        dictIterator* di = dictGetIterator(p);
        dictEntry* de;
        while ((de = dictNext(di)) != NULL) {
            ugTaskType* ptask = dictGetEntryVal(de); 
            luaworkUnrefFunction(server.ls, ptask->handle, NULL);            
        }
        dictReleaseIterator(di);
        dictRelease(p);
    }
}
コード例 #6
0
ファイル: pubsub.c プロジェクト: CNCBASHER/linuxcnc-1
/* Unsubscribe from all the channels. Return the number of channels the
 * client was subscribed from. */
int pubsubUnsubscribeAllChannels(redisClient *c, int notify) {
    dictIterator *di = dictGetSafeIterator(c->pubsub_channels);
    dictEntry *de;
    int count = 0;

    while((de = dictNext(di)) != NULL) {
        robj *channel = dictGetKey(de);

        count += pubsubUnsubscribeChannel(c,channel,notify);
    }
    dictReleaseIterator(di);
    return count;
}
コード例 #7
0
ファイル: engine.c プロジェクト: fizx/sit
void
_recurse_each(Callback *cb, dict *hash) {
	dictIterator * iterator = dictGetIterator(hash);
	dictEntry *next;
	while((next = dictNext(iterator))) {
		QueryNode *node = dictGetVal(next);
		cb->handler(cb, node);
		if(node->children) {
			_recurse_each(cb, node->children);
		}
	}
  dictReleaseIterator(iterator);
}
コード例 #8
0
ファイル: connection.c プロジェクト: fmardini/WebMux
static void shutdown_server(EV_P_ ev_signal *w, int revents) {
  IGNORE_VAR(w); IGNORE_VAR(revents);
  IGNORE_VAR(dictGenHashFunction); IGNORE_VAR(dictCreate); IGNORE_VAR(dictReplace); IGNORE_VAR(dictRelease);
  dictEntry *de;
  dictIterator *iter = dictGetIterator(active_connections);
  while ((de = dictNext(iter)) != NULL) {
    muxConn *mc = de->val;
    // stop any pending writes
    ev_io_stop(EV_A_ mc->watcher);
    disconnectAndClean(mc);
  }
  dictReleaseIterator(iter);
  ev_break(EV_A_ EVBREAK_ALL);
}
コード例 #9
0
ファイル: t_set.c プロジェクト: wenxueliu/draft
/* Move to the next entry in the set. Returns the object at the current
 * position.
 *
 * Since set elements can be internally be stored as redis objects or
 * simple arrays of integers, setTypeNext returns the encoding of the
 * set object you are iterating, and will populate the appropriate pointer
 * (objele) or (llele) accordingly.
 *
 * Note that both the objele and llele pointers should be passed and cannot
 * be NULL since the function will try to defensively populate the non
 * used field with values which are easy to trap if misused.
 *
 * When there are no longer elements -1 is returned.
 * Returned objects ref count is not incremented, so this function is
 * copy on write friendly. */
int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele) {
    if (si->encoding == REDIS_ENCODING_HT) {
        dictEntry *de = dictNext(si->di);
        if (de == NULL) return -1;
        *objele = dictGetKey(de);
        *llele = -123456789; /* Not needed. Defensive. */
    } else if (si->encoding == REDIS_ENCODING_INTSET) {
        if (!intsetGet(si->subject->ptr,si->ii++,llele))
            return -1;
        *objele = NULL; /* Not needed. Defensive. */
    } else {
        redisPanic("Wrong set encoding in setTypeNext");
    }
    return si->encoding;
}
コード例 #10
0
ファイル: slots.c プロジェクト: 107192468/codis
void
slotsmgrt_cleanup() {
    dictIterator *di = dictGetSafeIterator(server.slotsmgrt_cached_sockfds);
    dictEntry *de;
    while((de = dictNext(di)) != NULL) {
        slotsmgrt_sockfd *pfd = dictGetVal(de);
        if ((server.unixtime - pfd->lasttime) > 30) {
            redisLog(REDIS_WARNING, "slotsmgrt: timeout target %s, lasttime = %ld, now = %ld",
                   (char *)dictGetKey(de), pfd->lasttime, server.unixtime);
            dictDelete(server.slotsmgrt_cached_sockfds, dictGetKey(de));
            close(pfd->fd);
            zfree(pfd);
        }
    }
    dictReleaseIterator(di);
}
コード例 #11
0
ファイル: db.c プロジェクト: Elbandi/redis
void expirekeysGenericCommand(redisClient *c, robj *keypattern, robj *param, long offset) {
    dictIterator *di;
    dictEntry *de;
    sds pattern = keypattern->ptr;
    int plen = sdslen(pattern);
    unsigned long numkeys = 0, allkeys;
    time_t seconds;
    time_t when;

    if (getLongFromObjectOrReply(c, param, &seconds, NULL) != REDIS_OK) return;

    seconds -= offset;
    when = time(NULL)+seconds;

    di = dictGetIterator(c->db->dict);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetEntryKey(de);
        robj *keyobj;

        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
            keyobj = createStringObject(key,sdslen(key));
            if (seconds <= 0 && !server.loading && !server.masterhost) {
                robj *aux;

                redisAssert(dbDelete(c->db,keyobj));
                server.dirty++;
                numkeys++;

                /* Replicate/AOF this as an explicit DEL. */
                aux = createStringObject("DEL",3);
                rewriteClientCommandVector(c,2,aux,keyobj);
                decrRefCount(aux);
                touchWatchedKey(c->db,keyobj);
            } else {
                time_t when = time(NULL)+seconds;
                setExpire(c->db,keyobj,when);
                touchWatchedKey(c->db,keyobj);
                server.dirty++;
                numkeys++;
            }
            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);
    addReplyLongLong(c,numkeys);
}
コード例 #12
0
void call_bridge_event(struct redisClient *c,int triggle_place,int event_type)
{

    if(event_type==-1)
    {
        sds cmds=(sds)sdsdup(c->argv[0]->ptr);
        sdstolower(cmds);

        if(triggle_place==TRIGGLE_BEFORE) //no event given
        {
            cmds=sdscat(cmds,"ing");


        }
        if(triggle_place==TRIGGLE_AFTER)
        {
            cmds=sdscat(cmds,"ed");

        }

        event_type=process_trigglecmd(cmds);

  //      redisLog(REDIS_NOTICE,"cmds:%s id:%d",cmds,event_type);
        sdsfree(cmds);
    }

    if(event_type==-1)
        return;
    struct dictIterator *iter=dictGetIterator(server.bridge_db.triggle_scipts[c->db->id]);
    dictEntry *trigs;
    do{
        trigs=dictNext(iter);
        if(trigs!=NULL)
        {
            struct bridge_db_triggle_t * tmptrg=dictGetVal(trigs);

            if(tmptrg->event==event_type&&strncmp(c->argv[1]->ptr,dictGetKey(trigs),sdslen(dictGetKey(trigs)))==0){ //找到指定的类型事件
            //if(tmptrg->event==event_type){ //找到指定的类型事件
//                redisLog(REDIS_NOTICE,"triggle_event:%d,%s",event_type,(char *)dictGetKey(trigs));
                triggle_event(c,dictGetKey(trigs));
            }
        }
    }while(trigs!=NULL);
    dictReleaseIterator(iter);


}
コード例 #13
0
ファイル: latency.c プロジェクト: BruceZu/disque
/* Reset data for the specified event, or all the events data if 'event' is
 * NULL.
 *
 * Note: this is O(N) even when event_to_reset is not NULL because makes
 * the code simpler and we have a small fixed max number of events. */
int latencyResetEvent(char *event_to_reset) {
    dictIterator *di;
    dictEntry *de;
    int resets = 0;

    di = dictGetSafeIterator(server.latency_events);
    while((de = dictNext(di)) != NULL) {
        char *event = dictGetKey(de);

        if (event_to_reset == NULL || strcasecmp(event,event_to_reset) == 0) {
            dictDelete(server.latency_events, event);
            resets++;
        }
    }
    dictReleaseIterator(di);
    return resets;
}
コード例 #14
0
void rdb_save_triggles(rio *rdb)
{

    //save event 
    //db_num int int int int 
    //db 
    //scripts_num
    //key event lua_scripts 
    //key event lua_scripts 
    //.......
    dictIterator *di = NULL;
    dictEntry *de;   
    int i=0;
    for(i=0;i<server.dbnum;i++){
        int eventid=server.bridge_db.bridge_event[i]; 
        rioWrite(rdb,&eventid,4);
    }
    for(i=0;i<server.dbnum;i++)
    {
        dict *d = server.bridge_db.triggle_scipts[i];
        int mysize=dictSize(d);
        rioWrite(rdb,&mysize,4);
        if (dictSize(d) == 0) continue;
        di = dictGetSafeIterator(d);
        if (!di) {
            return ;
        }
        /* Iterate this DB writing every entry */
        while((de = dictNext(di)) != NULL) {
            sds keystr = dictGetKey(de);
            robj key;
            initStaticStringObject(key,keystr);
            if (rdbSaveStringObject(rdb,&key) == -1) return;

            struct bridge_db_triggle_t * tmptrg=dictGetVal(de);
            int event_id=tmptrg->event; 
            rioWrite(rdb,&event_id,4);
            int db_id=tmptrg->dbid; 
            rioWrite(rdb,&db_id,4);
            if (rdbSaveObjectType(rdb,tmptrg->lua_scripts) == -1) return ;
            if (rdbSaveObject(rdb,tmptrg->lua_scripts) == -1) return ; 
        }
    }
    if (di) dictReleaseIterator(di);
}
コード例 #15
0
ファイル: pubsub.c プロジェクト: xiaowei0516/redis_comment
/* PUBSUB command for Pub/Sub introspection. */
void pubsubCommand(client *c) {
    if (!strcasecmp(c->argv[1]->ptr,"channels") &&
        (c->argc == 2 || c->argc ==3))
    {
        /* PUBSUB CHANNELS [<pattern>] */
        sds pat = (c->argc == 2) ? NULL : c->argv[2]->ptr;
        dictIterator *di = dictGetIterator(server.pubsub_channels);
        dictEntry *de;
        long mblen = 0;
        void *replylen;

        replylen = addDeferredMultiBulkLength(c);
        while((de = dictNext(di)) != NULL) {
            robj *cobj = dictGetKey(de);
            sds channel = cobj->ptr;

            if (!pat || stringmatchlen(pat, sdslen(pat),
                                       channel, sdslen(channel),0))
            {
                addReplyBulk(c,cobj);
                mblen++;
            }
        }
        dictReleaseIterator(di);
        setDeferredMultiBulkLength(c,replylen,mblen);
    } else if (!strcasecmp(c->argv[1]->ptr,"numsub") && c->argc >= 2) {
        /* PUBSUB NUMSUB [Channel_1 ... Channel_N] */
        int j;

        addReplyMultiBulkLen(c,(c->argc-2)*2);
        for (j = 2; j < c->argc; j++) {
            list *l = dictFetchValue(server.pubsub_channels,c->argv[j]);

            addReplyBulk(c,c->argv[j]);
            addReplyLongLong(c,l ? listLength(l) : 0);
        }
    } else if (!strcasecmp(c->argv[1]->ptr,"numpat") && c->argc == 2) {
        /* PUBSUB NUMPAT */
        addReplyLongLong(c,listLength(server.pubsub_patterns));
    } else {
        addReplyErrorFormat(c,
            "Unknown PUBSUB subcommand or wrong number of arguments for '%s'",
            (char*)c->argv[1]->ptr);
    }
}
コード例 #16
0
/* Emit the commands needed to rebuild a set object.
 * The function returns 0 on error, 1 on success. */
int rewriteSetObject(rio *r, robj *key, robj *o) {
    long long count = 0, items = setTypeSize(o);

    if (o->encoding == REDIS_ENCODING_INTSET) {
        int ii = 0;
        int64_t llval;

        while(intsetGet(o->ptr,ii++,&llval)) {
            if (count == 0) {
                int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ?
                    REDIS_AOF_REWRITE_ITEMS_PER_CMD : items;

                if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0;
                if (rioWriteBulkString(r,"SADD",4) == 0) return 0;
                if (rioWriteBulkObject(r,key) == 0) return 0;
            }
            if (rioWriteBulkLongLong(r,llval) == 0) return 0;
            if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0;
            items--;
        }
    } else if (o->encoding == REDIS_ENCODING_HT) {
        dictIterator *di = dictGetIterator(o->ptr);
        dictEntry *de;

        while((de = dictNext(di)) != NULL) {
            robj *eleobj = dictGetKey(de);
            if (count == 0) {
                int cmd_items = (items > REDIS_AOF_REWRITE_ITEMS_PER_CMD) ?
                    REDIS_AOF_REWRITE_ITEMS_PER_CMD : items;

                if (rioWriteBulkCount(r,'*',2+cmd_items) == 0) return 0;
                if (rioWriteBulkString(r,"SADD",4) == 0) return 0;
                if (rioWriteBulkObject(r,key) == 0) return 0;
            }
            if (rioWriteBulkObject(r,eleobj) == 0) return 0;
            if (++count == REDIS_AOF_REWRITE_ITEMS_PER_CMD) count = 0;
            items--;
        }
        dictReleaseIterator(di);
    } else {
        redisPanic("Unknown set encoding");
    }
    return 1;
}
コード例 #17
0
ファイル: latency.c プロジェクト: BruceZu/disque
/* latencyCommand() helper to produce the reply for the LATEST subcommand,
 * listing the last latency sample for every event type registered so far. */
void latencyCommandReplyWithLatestEvents(client *c) {
    dictIterator *di;
    dictEntry *de;

    addReplyMultiBulkLen(c,dictSize(server.latency_events));
    di = dictGetIterator(server.latency_events);
    while((de = dictNext(di)) != NULL) {
        char *event = dictGetKey(de);
        struct latencyTimeSeries *ts = dictGetVal(de);
        int last = (ts->idx + LATENCY_TS_LEN - 1) % LATENCY_TS_LEN;

        addReplyMultiBulkLen(c,4);
        addReplyBulkCString(c,event);
        addReplyLongLong(c,ts->samples[last].time);
        addReplyLongLong(c,ts->samples[last].latency);
        addReplyLongLong(c,ts->max);
    }
    dictReleaseIterator(di);
}
コード例 #18
0
ファイル: mcache.c プロジェクト: truongminh/ccache
sds _masterGetStatus() {
    /*TODO: calculate cache increase speed,
     * then adopt a suitable stale-cache freeing strategy
     * Three involved params:
     * (1) master sleep,
     * (2) ae loop wait,
     * and (3) number of stale entries in one ae loop
     */

    sds status = sdsempty();//sdsfromlonglong(master_total_mem);
    status = sdscatprintf(status,"TOL RAM: %-6.2lfMB\tUSED RAM: %-6.2lf\n",
                          BYTES_TO_MEGABYTES(MASTER_MAX_AVAIL_MEM),
                          BYTES_TO_MEGABYTES(master_total_mem));
#if (CCACHE_LOG_LEVEL == CCACHE_DEBUG)
    status = sdscatprintf(status,"Detail:\n");
    status = sdscatprintf(status,"%-3s %-32s: %-6s\n"," ","KEY","MEM");
    dictIterator *di = dictGetIterator(master_cache);
    dictEntry *de;
    int idx = 1;
    while((de = dictNext(di)) != NULL) {
        objSds *value = (objSds*)dictGetEntryVal(de);
        if(value) {
            if(value->ptr) {
                status = sdscatprintf(status,"%-3d %-32s: %-6ld\n",
                                        idx++,
                                        (char*)dictGetEntryKey(de),
                                        sdslen(value->ptr));
            }
            else {
                status = sdscatprintf(status,"%-3d %-32s: %-6s\n",
                                        idx++,
                                        (char*)dictGetEntryKey(de),
                                        "WAITING");
            }
        }
    }
    dictReleaseIterator(di);
#endif
    sds status_reply = sdsnew("HTTP/1.1 200 OK\r\n");
    status_reply = sdscatprintf(status_reply,"Content-Length: %ld\r\n\r\n%s",sdslen(status),status);
    sdsfree(status);
    return status_reply;
}
コード例 #19
0
ファイル: vr_command.c プロジェクト: yanww-hz/vire
/* COMMAND <subcommand> <args> */
void commandCommand(client *c) {
    dictIterator *di;
    dictEntry *de;

    if (c->argc == 1) {
        addReplyMultiBulkLen(c, dictSize(server.commands));
        di = dictGetIterator(server.commands);
        while ((de = dictNext(di)) != NULL) {
            addReplyCommand(c, dictGetVal(de));
        }
        dictReleaseIterator(di);
    } else if (!strcasecmp(c->argv[1]->ptr, "info")) {
        int i;
        addReplyMultiBulkLen(c, c->argc-2);
        for (i = 2; i < c->argc; i++) {
            addReplyCommand(c, dictFetchValue(server.commands, c->argv[i]->ptr));
        }
    } else if (!strcasecmp(c->argv[1]->ptr, "count") && c->argc == 2) {
        addReplyLongLong(c, dictSize(server.commands));
    } else if (!strcasecmp(c->argv[1]->ptr,"getkeys") && c->argc >= 3) {
        struct redisCommand *cmd = lookupCommand(c->argv[2]->ptr);
        int *keys, numkeys, j;

        if (!cmd) {
            addReplyErrorFormat(c,"Invalid command specified");
            return;
        } else if ((cmd->arity > 0 && cmd->arity != c->argc-2) ||
                   ((c->argc-2) < -cmd->arity))
        {
            addReplyError(c,"Invalid number of arguments specified for command");
            return;
        }

        keys = getKeysFromCommand(cmd,c->argv+2,c->argc-2,&numkeys);
        addReplyMultiBulkLen(c,numkeys);
        for (j = 0; j < numkeys; j++) addReplyBulk(c,c->argv[keys[j]+2]);
        getKeysFreeResult(keys);
    } else {
        addReplyError(c, "Unknown subcommand or wrong number of arguments.");
        return;
    }
}
コード例 #20
0
ファイル: win32_cow.c プロジェクト: lrascao/redis
dictEntry *roZDictNext(roZDictIter *iter) {
    dictEntry *de = NULL;

    cowLock();
    if (iter->ar != NULL) {
        if (iter->pos >= 0 && iter->pos < iter->ar->numele) {
            de = &iter->ar->zde[iter->pos].de;
            iter->pos++;
        }
    } else if (iter->di != NULL) {
        de = dictNext(iter->di);
        iter->pos++;
    }
    if (de == NULL) {
        iter->pos = -1;
    }
    cowUnlock();

    return de;
}
コード例 #21
0
ファイル: win32_cow.c プロジェクト: lrascao/redis
/* convert a hash dictionary encoding to a dictionary array encoding */
cowDictZArray *cowConvertDictToZArray(dict *hdict) {
    dictIterator * di;
    dictEntry *de;
    int dsize;
    cowDictZArray *dar;
    int dcount = 0;
    dictZEntry *dezNew;
    dictZEntry *dezPrev;

    /* create copy */
    dsize = dictSize(hdict) > dictSlots(hdict) ? dictSize(hdict) : dictSlots(hdict);
    dar = (cowDictZArray *)zmalloc(sizeof(cowDictZArray) +
                                (dsize * sizeof(dictZEntry)) );

    /* copy all entries without refcounting or copying values */
    /* can't just memcpy the whole dictionary because entries are allocated */
    di = dictGetSafeIterator(hdict);
    dezNew = &dar->zde[0];
    dezPrev = NULL;
    while((de = dictNext(di)) != NULL && dcount < dsize) {
        double *score = (double *)dictGetEntryVal(de);
        /* copy score value into array
            and point val to score.  */
        dezNew->de.key = de->key;
        dezNew->score = *score;
        dezNew->de.val = &dezNew->score;
        /* fix next ptr of prev entry */
        if (dezPrev != NULL) {
            dezPrev->de.next = &dezNew->de;
        }
        dezPrev = dezNew;
        dezNew++;
        dcount++;
    }
    if (dezPrev != NULL) {
        dezPrev->de.next = NULL;
    }
    dar->numele = dcount;
    dictReleaseIterator(di);
    return dar;
}
コード例 #22
0
/* Unsubscribe from all the channels. Return the number of channels the
 * client was subscribed to. */
int smempubsubUnsubscribeAllChannels(client *c, int notify) 
{
    dictIterator *di = dictGetSafeIterator(c->smempubsub_channels);
    dictEntry *de;
    int count = 0;

    while((de = dictNext(di)) != NULL) {
        robj *channel = dictGetKey(de);

        count += smempubsubUnsubscribeChannel(c,channel,notify);
    }
    /* We were subscribed to nothing? Still reply to the client. */
    if (notify && count == 0) {
        addReply(c,shared.mbulkhdr[3]);
        addReply(c,shared.unsubscribebulk);
        addReply(c,shared.nullbulk);
        addReplyLongLong(c,dictSize(c->smempubsub_channels));
    }
    dictReleaseIterator(di);
    return count;
}
コード例 #23
0
ファイル: dbengine.c プロジェクト: aquirel/athenadb
valType dbSetTrunc(void)
{
    valType freed = 0, i;
    dictIterator *iter = NULL;
    dictEntry *entry = NULL;

    lockWrite(objectIndex);
    lockRead(sets);

    if (NULL == (iter = dictGetIterator(sets)))
    {
        unlockRead(sets);
        unlockWrite(objectIndex);
        return 0;
    }

    while (NULL != (entry = dictNext(iter)))
    {
        lockWrite(entry);
        freed += setTrunc((set *) dictGetEntryVal(entry));
        unlockWrite(entry);
    }

    for (i = 0; i < objectIndexLength; i++)
    {
        if (NULL != objectIndex[i] &&
            objectSet == objectIndex[i]->objectType)
        {
            freed += setTrunc(objectIndex[i]->objectPtr.setPtr);
        }
    }

    dictReleaseIterator(iter);

    unlockRead(sets);
    unlockWrite(objectIndex);

    return freed;
}
コード例 #24
0
ファイル: win32_cow.c プロジェクト: lrascao/redis
/* convert a hash dictionary encoding to a dictionary array encoding */
cowDictArray *cowConvertDictToArray(dict *hdict) {
    dictIterator * di;
    dictEntry *de;
    int dsize;
    cowDictArray *dar;
    int dcount = 0;
    dictEntry *deNew;
    dictEntry *dePrev;

    /* create copy */
    dsize = dictSize(hdict) > dictSlots(hdict) ? dictSize(hdict) : dictSlots(hdict);
    dar = (cowDictArray *)zmalloc(sizeof(cowDictArray) + (dsize * sizeof(dictEntry)));

    /* copy all entries without refcounting or copying values */
    /* can't just memcpy the whole dictionary because entries are allocated */
    di = dictGetSafeIterator(hdict);
    deNew = &dar->de[0];
    dePrev = NULL;
    while((de = dictNext(di)) != NULL && dcount < dsize) {
        /* copy object value to dict array
            Do not incr ref count.  */
        deNew->val = de->val;
        deNew->key = de->key;
        /* fix next ptr of prev entry */
        if (dePrev != NULL) {
            dePrev->next = deNew;
        }
        dePrev = deNew;
        deNew++;
        dcount++;
    }
    if (dePrev != NULL) {
        dePrev->next = NULL;
    }
    dar->numele = dcount;
    dictReleaseIterator(di);
    return dar;
}
コード例 #25
0
ファイル: dbengine.c プロジェクト: aquirel/athenadb
void cleanupDbEngine(void)
{
    dictIterator *i = NULL;
    dictEntry *de = NULL;
    valType c;

    unregisterSyncObject(sets);
    unregisterSyncObject(objectIndex);

    if (NULL == sets)
        return;

    i = dictGetIterator(sets);

    if (NULL != i)
    {
        while (NULL != (de = dictNext(i)))
        {
            set *setToDelete = (set *) dictGetEntryVal(de);

            if (!setToDelete->registered)
                setDestroy(setToDelete);
        }
    }

    dictReleaseIterator(i);
    dictRelease(sets);

    for (c = 0; c < objectIndexLength; c++)
        if (NULL != objectIndex[c])
        {
            dbObjectRelease((dbObject *) objectIndex[c]);
            free((void *) objectIndex[c]);
        }

    free((void *) objectIndex);
}
コード例 #26
0
ファイル: db.c プロジェクト: Elbandi/redis
void countCommand(redisClient *c) {
    dictIterator *di;
    dictEntry *de;
    sds pattern = c->argv[1]->ptr;
    int plen = sdslen(pattern), allkeys;
    unsigned long numkeys = 0;

    di = dictGetIterator(c->db->dict);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetEntryKey(de);
        robj *keyobj;

        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
            keyobj = createStringObject(key,sdslen(key));
            if (expireIfNeeded(c->db,keyobj) == 0) {
                numkeys++;
            }
            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);
    addReplyLongLong(c,numkeys);
}
コード例 #27
0
ファイル: counter.c プロジェクト: erikdubbelboer/discnt
void keysCommand(client *c) {
    dictIterator *di;
    dictEntry *de;
    sds pattern = c->argv[1]->ptr;
    int plen = sdslen(pattern), allkeys;
    unsigned long numkeys = 0;
    void *replylen = addDeferredMultiBulkLength(c);

    di = dictGetSafeIterator(server.counters);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetKey(de);
        robj *keyobj;

        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {
            keyobj = createStringObject(key,sdslen(key));
            addReplyBulk(c,keyobj);
            numkeys++;
            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);
    setDeferredMultiBulkLength(c,replylen,numkeys);
}
コード例 #28
0
ファイル: params_map.c プロジェクト: cf981378640/cosmonaut
char *params_map_serialize(params_map *p_map) {
  dictIterator *dict_iterator;
  dictEntry *dict_entry;
  param_entry *param;
  char *line, *result = NULL;

  dict_iterator = dictGetIterator(p_map);

  while((dict_entry = dictNext(dict_iterator)) != NULL) {
    param = (param_entry *)dictGetEntryVal(dict_entry);

    line = malloc_str(strlen("[") + strlen(param->name) + strlen(":") + strlen(param->val) + strlen("]"));
    sprintf(line, "[%s:%s]", param->name, param->val);

    result = str_concat(result, line);

    free(line);
  }

  free(dict_iterator);

  if (result == NULL) result = strdup("Params hash is empty");
  return result;
}
コード例 #29
0
void joinGeneric(redisClient *c,
                 jb_t        *jb) {
    if (jb->w.nob > 1) {
        addReply(c, shared.join_m_obc);
        return;
    }
    Order_by         = jb->w.nob;
    Order_by_col_val = NULL;

    /* sort queried-columns to queried-indices */
    jqo_t o_csort_order[MAX_COLUMN_PER_TABLE];
    jqo_t csort_order  [MAX_COLUMN_PER_TABLE];
    for (int i = 0; i < jb->qcols; i++) {
        for (int j = 0; j < jb->n_ind; j++) {
            if (jb->j_tbls[i] == Index[server.dbid][jb->j_indxs[j]].table) {
                csort_order[i].t = jb->j_tbls[i];
                csort_order[i].i = j;
                csort_order[i].c = jb->j_cols[i];
                csort_order[i].n = i;
            }
        }
    }
    memcpy(&o_csort_order, &csort_order, sizeof(jqo_t) * jb->qcols);
    qsort(&csort_order, jb->qcols, sizeof(jqo_t), cmp_jqo);

    /* reorder queried-columns to queried-indices, will sort @ output time */
    bool reordered = 0;
    for (int i = 0; i < jb->qcols; i++) {
        if (jb->j_tbls[i] != csort_order[i].t ||
            jb->j_cols[i] != csort_order[i].c) {
                reordered = 1;
                jb->j_tbls[i] = csort_order[i].t;
                jb->j_cols[i] = csort_order[i].c;
        }
    }

    cswc_t *w      = &jb->w; /* makes coding more compact */
    w->tmatch      = w->obt[0]; /* HACK: initOBsort needs w->tmatch */
    list   *ll     = initOBsort(Order_by, w);
    uchar  pk1type = Tbl[server.dbid]
                         [Index[server.dbid][jb->j_indxs[0]].table].col_type[0];
    bt    *jbtr    = createJoinResultSet(pk1type);

    robj  *rset[MAX_JOIN_INDXS];
    for (int i = 1; i < jb->n_ind; i++) {
        rset[i] = createValSetObject();
    }

    int j_ind_len [MAX_JOIN_INDXS];
    int jind_ncols[MAX_JOIN_INDXS];
    join_add_cols_t jc; /* these dont change in the loop below */
    jc.qcols      = jb->qcols;
    jc.j_tbls     = jb->j_tbls;
    jc.j_cols     = jb->j_cols;
    jc.jind_ncols = jind_ncols;
    jc.j_ind_len  = j_ind_len;
    jc.jbtr       = jbtr;
    
    for (int i = 0; i < jb->n_ind; i++) { /* iterate join indices */
        btEntry    *be, *nbe;
        j_ind_len[i] = 0;
        jc.index     = i;
        jc.itable    = Index[server.dbid][jb->j_indxs[i]].table;
        robj *btt    = lookupKeyRead(c->db, Tbl[server.dbid][jc.itable].name);
        jc.btr       = (bt *)btt->ptr;
        jc.virt      = Index[server.dbid][jb->j_indxs[i]].virt;
     
        if (w->low) { /* RANGE QUERY */
            if (jc.virt) { /* PK */
                btSIter *bi = btGetRangeIterator(jc.btr, w->low, w->high);
                while ((be = btRangeNext(bi)) != NULL) {
                    jc.ajk    = be->key;
                    jc.rrow   = be->val;
                    joinAddColsFromInd(&jc, rset, w);
                }
                btReleaseRangeIterator(bi);
            } else {       /* FK */
                robj    *ind  = Index[server.dbid][jb->j_indxs[i]].obj;
                robj    *ibtt = lookupKey(c->db, ind);
                bt      *ibtr = (bt *)ibtt->ptr;
                btSIter *bi   = btGetRangeIterator(ibtr, w->low, w->high);
                while ((be = btRangeNext(bi)) != NULL) {
                    jc.ajk        = be->key;
                    bt      *nbtr = be->val;
                    btSIter *nbi  = btGetFullRangeIterator(nbtr);
                    while ((nbe = btRangeNext(nbi)) != NULL) {
                        jc.rrow = btFindVal(jc.btr, nbe->key);
                        joinAddColsFromInd(&jc, rset, w);
                    }
                    btReleaseRangeIterator(nbi);
                }
                btReleaseRangeIterator(bi);
            }
        } else {      /* IN() QUERY */
            listNode *ln;
            listIter *li  = listGetIterator(w->inl, AL_START_HEAD);
            if (jc.virt) {
                while((ln = listNext(li)) != NULL) {
                    jc.ajk  = ln->value;
                    jc.rrow = btFindVal(jc.btr, jc.ajk);
                    if (jc.rrow) joinAddColsFromInd(&jc, rset, w);
                }
            } else {
                btSIter *nbi;
                robj *ind    = Index[server.dbid][jb->j_indxs[i]].obj;
                robj *ibtt   = lookupKey(c->db, ind);   
                bt   *ibtr   = (bt *)ibtt->ptr;
                while((ln = listNext(li)) != NULL) {
                    jc.ajk   = ln->value;
                    bt *nbtr = btIndFindVal(ibtr, jc.ajk);
                    if (nbtr) {
                        nbi  = btGetFullRangeIterator(nbtr);
                        while ((nbe = btRangeNext(nbi)) != NULL) {
                            jc.rrow = btFindVal(jc.btr, nbe->key);
                            joinAddColsFromInd(&jc, rset, w);
                        }
                        btReleaseRangeIterator(nbi);
                    }
                }
            }
            listReleaseIterator(li);
        }
    }

    /* cant join if one table had ZERO rows */
    bool one_empty = 0;
    if (jbtr->numkeys == 0) one_empty = 1;
    else {
        for (int i = 1; i < jb->n_ind; i++) {
            if (dictSize((dict *)rset[i]->ptr) == 0) {
                one_empty = 1;
                break;
            }
        }
    }

    LEN_OBJ

    bool        err   = 0;
    long        sent  = 0;
    btIterator *bi    = NULL; /* B4 GOTO */
    char       *reply = NULL; /* B4 GOTO */
    if (!one_empty) {
        int reply_size = 0;
        for (int i = 0; i < jb->n_ind; i++) { // get maxlen possbl 4 joined row
            reply_size += j_ind_len[i] + 1;
        }
        reply = malloc(reply_size); /* freed after while() loop */
    
        build_jrow_reply_t bjr; /* none of these change during a join */
        bzero(&bjr, sizeof(build_jrow_reply_t));
        bjr.j.c           = c;
        bjr.j.jind_ncols  = jind_ncols;
        bjr.j.reply       = reply;
        bjr.j.csort_order = csort_order;
        bjr.j.reordered   = reordered;
        bjr.j.qcols       = jb->qcols;
        bjr.n_ind         = jb->n_ind;
        bjr.card          = &card;
        bjr.j.obt         = w->obt[0];
        bjr.j.obc         = w->obc[0];
        bjr.j_indxs       = jb->j_indxs;
        bjr.j.ll          = ll;
        bjr.j.cstar       = jb->cstar;

        joinRowEntry *be;
        bi = btGetJoinFullRangeIterator(jbtr, pk1type);
        while ((be = btJoinRangeNext(bi, pk1type)) != NULL) { /* iter BT */
            listNode *ln;
            bjr.jk        = be->key;
            list     *jll = (list *)be->val;
            listIter *li  = listGetIterator(jll, AL_START_HEAD);
            while((ln = listNext(li)) != NULL) {        /* iter LIST */
                char *first_entry;
                char *item = ln->value;
                if (bjr.j.obt == Index[server.dbid][bjr.j_indxs[0]].table) {
                    obsl_t *ob       = (obsl_t *)item;
                    Order_by_col_val = ob->keys[0];
                    first_entry      = (char *)ob->row;
                } else {
                    first_entry      = item;
                }
                for (int j = 0; j < jind_ncols[0]; j++) {
                    Rcols[0][j]  = (char **)first_entry;
                    first_entry += PTR_SIZE;
                    memcpy(&Rc_lens[0][j], first_entry, UINT_SIZE);
                    first_entry += UINT_SIZE;
                }
    
                if (!buildJRowReply(&bjr, 1, rset)) {
                    err = 1;
                    goto join_end;
                }
            }
            listReleaseIterator(li);
        }

        if (Order_by) {
            sent = sortJoinOrderByAndReply(c, &bjr, w);
            if (sent == -1) err = 1;
            releaseOBsort(ll);
        }
    }

join_end:
    if (bi)    btReleaseJoinRangeIterator(bi);
    if (reply) free(reply);

    /* free joinRowEntry malloc from joinAddColsFromInd() */
    bool  is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[0]].table);
    btJoinRelease(jbtr, jind_ncols[0], is_ob, freeListOfIndRow);

    /* free joinRowEntry malloc from joinAddColsFromInd() */
    dictEntry *de;
    for (int i = 1; i < jb->n_ind; i++) {
        dict *set   = rset[i]->ptr;
        bool  is_ob = (w->obt[0] == Index[server.dbid][jb->j_indxs[i]].table);
        dictIterator *di = dictGetIterator(set);
        while((de = dictNext(di)) != NULL) {
            robj *val  = dictGetEntryVal(de);
            dict *iset = val->ptr;
            freeDictOfIndRow(iset, jind_ncols[i], is_ob);
        }
        dictReleaseIterator(di);
    }

    for (int i = 1; i < jb->n_ind; i++) {
        decrRefCount(rset[i]);
    }

    if (err) return;
    if (w->lim != -1 && sent < card) card = sent;
    if (jb->cstar) {
        lenobj->ptr = sdscatprintf(sdsempty(), ":%ld\r\n", card);
    } else {
        lenobj->ptr = sdscatprintf(sdsempty(), "*%ld\r\n", card);
        if (w->ovar) incrOffsetVar(c, w, card);
    }
}
コード例 #30
0
ファイル: sort.c プロジェクト: JoonyLi/redis-android
/* 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);
}