#define REDIS_MAXIDLETIME (60*5) /* default client timeout */
#define REDIS_IOBUF_LEN 1024
#define REDIS_LOADBUF_LEN 1024
-#define REDIS_STATIC_ARGS 4
+#define REDIS_STATIC_ARGS 8
#define REDIS_DEFAULT_DBNUM 16
#define REDIS_CONFIGLINE_MAX 1024
#define REDIS_OBJFREELIST_MAX 1000000 /* Max number of objects to cache */
robj *val; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
* field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
off_t page; /* Swap page where to read/write the object */
- off_t pages; /* Swap pages needed to safe object. PREPARE_SWAP return val */
+ off_t pages; /* Swap pages needed to save object. PREPARE_SWAP return val */
int canceled; /* True if this command was canceled by blocking side of VM */
pthread_t thread; /* ID of the thread processing this entry */
} iojob;
static int rdbSaveBackground(char *filename);
static robj *createStringObject(char *ptr, size_t len);
static robj *dupStringObject(robj *o);
-static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc);
+static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc);
static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc);
static int syncWithMaster(void);
static robj *tryObjectSharing(robj *o);
static void hgetallCommand(redisClient *c);
static void hexistsCommand(redisClient *c);
static void configCommand(redisClient *c);
+ static void hincrbyCommand(redisClient *c);
/*================================= Globals ================================= */
{"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
+ {"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
{"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
{"hlen",hlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
if (server.appendonly && server.dirty-dirty)
feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc);
if (server.dirty-dirty && listLength(server.slaves))
- replicationFeedSlaves(server.slaves,cmd,c->db->id,c->argv,c->argc);
+ replicationFeedSlaves(server.slaves,c->db->id,c->argv,c->argc);
if (listLength(server.monitors))
- replicationFeedSlaves(server.monitors,cmd,c->db->id,c->argv,c->argc);
+ replicationFeedSlaves(server.monitors,c->db->id,c->argv,c->argc);
server.stat_numcommands++;
}
return 1;
}
-static void replicationFeedSlaves(list *slaves, struct redisCommand *cmd, int dictid, robj **argv, int argc) {
+static void replicationFeedSlaves(list *slaves, int dictid, robj **argv, int argc) {
listNode *ln;
listIter li;
int outc = 0, j;
robj **outv;
- /* (args*2)+1 is enough room for args, spaces, newlines */
- robj *static_outv[REDIS_STATIC_ARGS*2+1];
+ /* We need 1+(ARGS*3) objects since commands are using the new protocol
+ * and we one 1 object for the first "*<count>\r\n" multibulk count, then
+ * for every additional object we have "$<count>\r\n" + object + "\r\n". */
+ robj *static_outv[REDIS_STATIC_ARGS*3+1];
+ robj *lenobj;
if (argc <= REDIS_STATIC_ARGS) {
outv = static_outv;
} else {
- outv = zmalloc(sizeof(robj*)*(argc*2+1));
+ outv = zmalloc(sizeof(robj*)*(argc*3+1));
}
-
+
+ lenobj = createObject(REDIS_STRING,
+ sdscatprintf(sdsempty(), "*%d\r\n", argc));
+ lenobj->refcount = 0;
+ outv[outc++] = lenobj;
for (j = 0; j < argc; j++) {
- if (j != 0) outv[outc++] = shared.space;
- if ((cmd->flags & REDIS_CMD_BULK) && j == argc-1) {
- robj *lenobj;
-
- lenobj = createObject(REDIS_STRING,
- sdscatprintf(sdsempty(),"%lu\r\n",
- (unsigned long) stringObjectLen(argv[j])));
- lenobj->refcount = 0;
- outv[outc++] = lenobj;
- }
+ lenobj = createObject(REDIS_STRING,
+ sdscatprintf(sdsempty(),"$%lu\r\n",
+ (unsigned long) stringObjectLen(argv[j])));
+ lenobj->refcount = 0;
+ outv[outc++] = lenobj;
outv[outc++] = argv[j];
+ outv[outc++] = shared.crlf;
}
- outv[outc++] = shared.crlf;
/* Increment all the refcounts at start and decrement at end in order to
* be sure to free objects if there is no slave in a replication state
} else {
return;
}
- if (!(c->flags & REDIS_BLOCKED))
- processInputBuffer(c);
+ processInputBuffer(c);
}
static int selectDb(redisClient *c, int id) {
addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",update == 0));
}
+ static void hincrbyCommand(redisClient *c) {
+ int update = 0;
+ long long value = 0, incr = 0;
+ robj *o = lookupKeyWrite(c->db,c->argv[1]);
+
+ if (o == NULL) {
+ o = createHashObject();
+ dictAdd(c->db->dict,c->argv[1],o);
+ incrRefCount(c->argv[1]);
+ } else {
+ if (o->type != REDIS_HASH) {
+ addReply(c,shared.wrongtypeerr);
+ return;
+ }
+ }
+
+ robj *o_incr = getDecodedObject(c->argv[3]);
+ incr = strtoll(o_incr->ptr, NULL, 10);
+ decrRefCount(o_incr);
+
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
+ unsigned char *zm = o->ptr;
+ unsigned char *zval;
+ unsigned int zvlen;
+
+ /* Find value if already present in hash */
+ if (zipmapGet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
+ &zval,&zvlen)) {
+ /* strtoll needs the char* to have a trailing \0, but
+ * the zipmap doesn't include them. */
+ sds szval = sdsnewlen(zval, zvlen);
+ value = strtoll(szval,NULL,10);
+ sdsfree(szval);
+ }
+
+ value += incr;
+ sds svalue = sdscatprintf(sdsempty(),"%lld",value);
+ zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
+ (unsigned char*)svalue,sdslen(svalue),&update);
+ sdsfree(svalue);
+ o->ptr = zm;
+
+ /* Check if the zipmap needs to be converted
+ * if this was not an update. */
+ if (!update && zipmapLen(zm) > server.hash_max_zipmap_entries)
+ convertToRealHash(o);
+ } else {
+ robj *hval;
+ dictEntry *de;
+
+ /* Find value if already present in hash */
+ de = dictFind(o->ptr,c->argv[2]);
+ if (de != NULL) {
+ hval = dictGetEntryVal(de);
+ if (hval->encoding == REDIS_ENCODING_RAW)
+ value = strtoll(hval->ptr,NULL,10);
+ else if (hval->encoding == REDIS_ENCODING_INT)
+ value = (long)hval->ptr;
+ else
+ redisAssert(1 != 1);
+ }
+
+ value += incr;
+ hval = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
+ tryObjectEncoding(hval);
+ if (dictReplace(o->ptr,c->argv[2],hval)) {
+ incrRefCount(c->argv[2]);
+ }
+ }
+
+ server.dirty++;
+ addReplyLong(c, value);
+ }
+
static void hgetCommand(redisClient *c) {
robj *o;