diff --git a/src/cluster.c b/src/cluster.c index 76ea894de0fc850e69f2a8f6301d3f30c4ddeb2a..b57dd48ca8588817d0769a674966cc53a63b7345 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1270,6 +1270,7 @@ file_wr_err: strerror(errno)); fclose(fp); close(fd); + return; file_rd_err: redisLog(REDIS_WARNING,"Can't read from tmp file for MIGRATE: %s", @@ -1278,6 +1279,7 @@ file_rd_err: strerror(errno)); fclose(fp); close(fd); + return; socket_wr_err: redisLog(REDIS_NOTICE,"Can't write to target node for MIGRATE: %s", @@ -1286,6 +1288,7 @@ socket_wr_err: strerror(errno)); fclose(fp); close(fd); + return; socket_rd_err: redisLog(REDIS_NOTICE,"Can't read from target node for MIGRATE: %s", @@ -1294,6 +1297,81 @@ socket_rd_err: strerror(errno)); fclose(fp); close(fd); + return; +} + +/* DUMP keyname + * DUMP is actually not used by Redis Cluster but it is the obvious + * complement of RESTORE and can be useful for different applications. */ +void dumpCommand(redisClient *c) { + char buf[64]; + FILE *fp; + robj *o, *dumpobj; + sds dump = NULL; + off_t payload_len; + unsigned int type; + + /* Check if the key is here. */ + if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) { + addReply(c,shared.nullbulk); + return; + } + + /* Create temp file */ + snprintf(buf,sizeof(buf),"redis-dump-%d.tmp",getpid()); + fp = fopen(buf,"w+"); + if (!fp) { + redisLog(REDIS_WARNING,"Can't open tmp file for MIGRATE: %s", + strerror(errno)); + addReplyErrorFormat(c,"DUMP failed, tmp file creation error: %s.", + strerror(errno)); + return; + } + unlink(buf); + + /* Dump the serailized object and read it back in memory. + * We prefix it with a one byte containing the type ID. + * This is the serialization format understood by RESTORE. */ + if (rdbSaveObject(fp,o) == -1) goto file_wr_err; + payload_len = ftello(fp); + if (fseeko(fp,0,SEEK_SET) == -1) goto file_rd_err; + dump = sdsnewlen(NULL,payload_len+1); + if (payload_len && fread(dump+1,payload_len,1,fp) != 1) goto file_rd_err; + fclose(fp); + type = o->type; + if (type == REDIS_LIST && o->encoding == REDIS_ENCODING_ZIPLIST) + type = REDIS_LIST_ZIPLIST; + else if (type == REDIS_HASH && o->encoding == REDIS_ENCODING_ZIPMAP) + type = REDIS_HASH_ZIPMAP; + else if (type == REDIS_SET && o->encoding == REDIS_ENCODING_INTSET) + type = REDIS_SET_INTSET; + else + type = o->type; + dump[0] = type; + + /* Transfer to the client */ + dumpobj = createObject(REDIS_STRING,dump); + addReplyBulk(c,dumpobj); + decrRefCount(dumpobj); + return; + +file_wr_err: + redisLog(REDIS_WARNING,"Can't write on tmp file for DUMP: %s", + strerror(errno)); + addReplyErrorFormat(c,"DUMP failed, tmp file write error: %s.", + strerror(errno)); + sdsfree(dump); + fclose(fp); + return; + +file_rd_err: + redisLog(REDIS_WARNING,"Can't read from tmp file for DUMP: %s", + strerror(errno)); + addReplyErrorFormat(c,"DUMP failed, tmp file read error: %s.", + strerror(errno)); + sdsfree(dump); + fclose(fp); + return; } /* ----------------------------------------------------------------------------- diff --git a/src/redis.c b/src/redis.c index 8b8c49eb7e5abf1def75bb1762399a36c266f9b6..1cc8cc75f6c900b9707368e71f90dedc5e003abd 100644 --- a/src/redis.c +++ b/src/redis.c @@ -189,8 +189,9 @@ struct redisCommand redisCommandTable[] = { {"watch",watchCommand,-2,0,noPreloadGetKeys,1,-1,1,0,0}, {"unwatch",unwatchCommand,1,0,NULL,0,0,0,0,0}, {"cluster",clusterCommand,-2,0,NULL,0,0,0,0,0}, - {"restore",restoreCommand,3,0,NULL,0,0,0,0,0}, - {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0} + {"restore",restoreCommand,4,0,NULL,0,0,0,0,0}, + {"migrate",migrateCommand,6,0,NULL,0,0,0,0,0}, + {"dump",dumpCommand,2,0,NULL,0,0,0,0,0} }; /*============================ Utility functions ============================ */ diff --git a/src/redis.h b/src/redis.h index 5b403798bf037a2f3fd2ec06692a23ce139d7ff1..91a64ecfddc049eddd2473b7c370ca2ce11fd3c7 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1180,6 +1180,7 @@ void unwatchCommand(redisClient *c); void clusterCommand(redisClient *c); void restoreCommand(redisClient *c); void migrateCommand(redisClient *c); +void dumpCommand(redisClient *c); #if defined(__GNUC__) void *calloc(size_t count, size_t size) __attribute__ ((deprecated)); diff --git a/src/sds.c b/src/sds.c index 7cb43962e451a5518e4aed1adb4615f53d16e0ef..8c7540990e8154d0326f885e2a529da062acf21f 100644 --- a/src/sds.c +++ b/src/sds.c @@ -51,7 +51,11 @@ static void sdsOomAbort(void) { sds sdsnewlen(const void *init, size_t initlen) { struct sdshdr *sh; - sh = zmalloc(sizeof(struct sdshdr)+initlen+1); + if (init) { + sh = zmalloc(sizeof(struct sdshdr)+initlen+1); + } else { + sh = zcalloc(sizeof(struct sdshdr)+initlen+1); + } #ifdef SDS_ABORT_ON_OOM if (sh == NULL) sdsOomAbort(); #else @@ -59,10 +63,8 @@ sds sdsnewlen(const void *init, size_t initlen) { #endif sh->len = initlen; sh->free = 0; - if (initlen) { - if (init) memcpy(sh->buf, init, initlen); - else memset(sh->buf,0,initlen); - } + if (initlen && init) + memcpy(sh->buf, init, initlen); sh->buf[initlen] = '\0'; return (char*)sh->buf; }