static void lsetCommand(redisClient *c);
static void saddCommand(redisClient *c);
static void sremCommand(redisClient *c);
+static void smoveCommand(redisClient *c);
static void sismemberCommand(redisClient *c);
static void scardCommand(redisClient *c);
static void sinterCommand(redisClient *c);
static void mgetCommand(redisClient *c);
static void monitorCommand(redisClient *c);
static void expireCommand(redisClient *c);
+static void getSetCommand(redisClient *c);
/*================================= Globals ================================= */
{"lrem",lremCommand,4,REDIS_CMD_BULK},
{"sadd",saddCommand,3,REDIS_CMD_BULK},
{"srem",sremCommand,3,REDIS_CMD_BULK},
+ {"smove",smoveCommand,4,REDIS_CMD_BULK},
{"sismember",sismemberCommand,3,REDIS_CMD_BULK},
{"scard",scardCommand,2,REDIS_CMD_INLINE},
{"sinter",sinterCommand,-2,REDIS_CMD_INLINE},
{"smembers",sinterCommand,2,REDIS_CMD_INLINE},
{"incrby",incrbyCommand,3,REDIS_CMD_INLINE},
{"decrby",decrbyCommand,3,REDIS_CMD_INLINE},
+ {"getset",getSetCommand,3,REDIS_CMD_BULK},
{"randomkey",randomkeyCommand,1,REDIS_CMD_INLINE},
{"select",selectCommand,2,REDIS_CMD_INLINE},
{"move",moveCommand,3,REDIS_CMD_INLINE},
return removed;
}
+static int yesnotoi(char *s) {
+ if (!strcasecmp(s,"yes")) return 1;
+ else if (!strcasecmp(s,"no")) return 0;
+ else return -1;
+}
+
/* I agree, this is a very rudimental way to load a configuration...
will improve later if the config gets more complex */
static void loadServerConfig(char *filename) {
sdstolower(argv[0]);
/* Execute config directives */
- if (!strcmp(argv[0],"timeout") && argc == 2) {
+ if (!strcasecmp(argv[0],"timeout") && argc == 2) {
server.maxidletime = atoi(argv[1]);
if (server.maxidletime < 1) {
err = "Invalid timeout value"; goto loaderr;
}
- } else if (!strcmp(argv[0],"port") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"port") && argc == 2) {
server.port = atoi(argv[1]);
if (server.port < 1 || server.port > 65535) {
err = "Invalid port"; goto loaderr;
}
- } else if (!strcmp(argv[0],"bind") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
server.bindaddr = zstrdup(argv[1]);
- } else if (!strcmp(argv[0],"save") && argc == 3) {
+ } else if (!strcasecmp(argv[0],"save") && argc == 3) {
int seconds = atoi(argv[1]);
int changes = atoi(argv[2]);
if (seconds < 1 || changes < 0) {
err = "Invalid save parameters"; goto loaderr;
}
appendServerSaveParams(seconds,changes);
- } else if (!strcmp(argv[0],"dir") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
if (chdir(argv[1]) == -1) {
redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
argv[1], strerror(errno));
exit(1);
}
- } else if (!strcmp(argv[0],"loglevel") && argc == 2) {
- if (!strcmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
- else if (!strcmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
- else if (!strcmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
+ } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
+ if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
+ else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
+ else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
else {
err = "Invalid log level. Must be one of debug, notice, warning";
goto loaderr;
}
- } else if (!strcmp(argv[0],"logfile") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
FILE *fp;
server.logfile = zstrdup(argv[1]);
- if (!strcmp(server.logfile,"stdout")) {
+ if (!strcasecmp(server.logfile,"stdout")) {
zfree(server.logfile);
server.logfile = NULL;
}
}
fclose(fp);
}
- } else if (!strcmp(argv[0],"databases") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
server.dbnum = atoi(argv[1]);
if (server.dbnum < 1) {
err = "Invalid number of databases"; goto loaderr;
}
- } else if (!strcmp(argv[0],"slaveof") && argc == 3) {
+ } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
server.masterhost = sdsnew(argv[1]);
server.masterport = atoi(argv[2]);
server.replstate = REDIS_REPL_CONNECT;
- } else if (!strcmp(argv[0],"glueoutputbuf") && argc == 2) {
- sdstolower(argv[1]);
- if (!strcmp(argv[1],"yes")) server.glueoutputbuf = 1;
- else if (!strcmp(argv[1],"no")) server.glueoutputbuf = 0;
- else {
+ } else if (!strcasecmp(argv[0],"glueoutputbuf") && argc == 2) {
+ if ((server.glueoutputbuf = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
- } else if (!strcmp(argv[0],"shareobjects") && argc == 2) {
- sdstolower(argv[1]);
- if (!strcmp(argv[1],"yes")) server.shareobjects = 1;
- else if (!strcmp(argv[1],"no")) server.shareobjects = 0;
- else {
+ } else if (!strcasecmp(argv[0],"shareobjects") && argc == 2) {
+ if ((server.shareobjects = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
- } else if (!strcmp(argv[0],"daemonize") && argc == 2) {
- sdstolower(argv[1]);
- if (!strcmp(argv[1],"yes")) server.daemonize = 1;
- else if (!strcmp(argv[1],"no")) server.daemonize = 0;
- else {
+ } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
+ if ((server.daemonize = yesnotoi(argv[1])) == -1) {
err = "argument must be 'yes' or 'no'"; goto loaderr;
}
- } else if (!strcmp(argv[0],"requirepass") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
server.requirepass = zstrdup(argv[1]);
- } else if (!strcmp(argv[0],"pidfile") && argc == 2) {
+ } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
server.pidfile = zstrdup(argv[1]);
+ } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
+ server.dbfilename = zstrdup(argv[1]);
} else {
err = "Bad directive or wrong number of arguments"; goto loaderr;
}
static struct redisCommand *lookupCommand(char *name) {
int j = 0;
while(cmdTable[j].name != NULL) {
- if (!strcmp(name,cmdTable[j].name)) return &cmdTable[j];
+ if (!strcasecmp(name,cmdTable[j].name)) return &cmdTable[j];
j++;
}
return NULL;
struct redisCommand *cmd;
long long dirty;
- sdstolower(c->argv[0]->ptr);
/* The QUIT command is handled as a special case. Normal command
* procs are unable to close the client connection safely */
- if (!strcmp(c->argv[0]->ptr,"quit")) {
+ if (!strcasecmp(c->argv[0]->ptr,"quit")) {
freeClient(c);
return 0;
}
/* We require at least four bytes compression for this to be worth it */
outlen = sdslen(obj->ptr)-4;
if (outlen <= 0) return 0;
- if ((out = zmalloc(outlen)) == NULL) return 0;
+ if ((out = zmalloc(outlen+1)) == NULL) return 0;
comprlen = lzf_compress(obj->ptr, sdslen(obj->ptr), out, outlen);
if (comprlen == 0) {
zfree(out);
/* Try LZF compression - under 20 bytes it's unable to compress even
* aaaaaaaaaaaaaaaaaa so skip it */
- if (len > 20) {
+ if (1 && len > 20) {
int retval;
retval = rdbSaveLzfStringObject(fp,obj);
}
}
+static void getSetCommand(redisClient *c) {
+ getCommand(c);
+ if (dictAdd(c->db->dict,c->argv[1],c->argv[2]) == DICT_ERR) {
+ dictReplace(c->db->dict,c->argv[1],c->argv[2]);
+ } else {
+ incrRefCount(c->argv[1]);
+ }
+ incrRefCount(c->argv[2]);
+ server.dirty++;
+ removeExpire(c->db,c->argv[1]);
+}
+
static void mgetCommand(redisClient *c) {
int j;
/* XXX: TODO kill the child if there is a bgsave in progress */
if (rdbSave(server.dbfilename) == REDIS_OK) {
if (server.daemonize) {
- unlink(server.pidfile);
+ unlink(server.pidfile);
}
+ redisLog(REDIS_WARNING,"%zu bytes used at exit",zmalloc_used_memory());
redisLog(REDIS_WARNING,"Server exit now, bye bye...");
exit(1);
} else {
}
}
+static void smoveCommand(redisClient *c) {
+ robj *srcset, *dstset;
+
+ srcset = lookupKeyWrite(c->db,c->argv[1]);
+ dstset = lookupKeyWrite(c->db,c->argv[2]);
+
+ /* If the source key does not exist return 0, if it's of the wrong type
+ * raise an error */
+ if (srcset == NULL || srcset->type != REDIS_SET) {
+ addReply(c, srcset ? shared.wrongtypeerr : shared.czero);
+ return;
+ }
+ /* Error if the destination key is not a set as well */
+ if (dstset && dstset->type != REDIS_SET) {
+ addReply(c,shared.wrongtypeerr);
+ return;
+ }
+ /* Remove the element from the source set */
+ if (dictDelete(srcset->ptr,c->argv[3]) == DICT_ERR) {
+ /* Key not found in the src set! return zero */
+ addReply(c,shared.czero);
+ return;
+ }
+ server.dirty++;
+ /* Add the element to the destination set */
+ if (!dstset) {
+ dstset = createSetObject();
+ dictAdd(c->db->dict,c->argv[2],dstset);
+ incrRefCount(c->argv[2]);
+ }
+ if (dictAdd(dstset->ptr,c->argv[3],NULL) == DICT_OK)
+ incrRefCount(c->argv[3]);
+ addReply(c,shared.cone);
+}
+
static void sismemberCommand(redisClient *c) {
robj *set;
"connected_slaves:%d\r\n"
"used_memory:%zu\r\n"
"changes_since_last_save:%lld\r\n"
+ "bgsave_in_progress:%d\r\n"
"last_save_time:%d\r\n"
"total_connections_received:%lld\r\n"
"total_commands_processed:%lld\r\n"
listLength(server.slaves),
server.usedmemory,
server.dirty,
+ server.bgsaveinprogress,
server.lastsave,
server.stat_numconnections,
server.stat_numcommands,