X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/040b0ade7dd9d30210ec89182bbe4d416416ed53..6d61e5bf5b3bdbdfa3032b2009120c3cceb64607:/src/db.c diff --git a/src/db.c b/src/db.c index 47994df2..9620b6e8 100644 --- a/src/db.c +++ b/src/db.c @@ -79,7 +79,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) { sds copy = sdsdup(key->ptr); int retval = dictAdd(db->dict, copy, val); - redisAssert(retval == REDIS_OK); + redisAssertWithInfo(NULL,key,retval == REDIS_OK); if (server.cluster_enabled) SlotToKeyAdd(key); } @@ -91,7 +91,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) { void dbOverwrite(redisDb *db, robj *key, robj *val) { struct dictEntry *de = dictFind(db->dict,key->ptr); - redisAssert(de != NULL); + redisAssertWithInfo(NULL,key,de != NULL); dictReplace(db->dict, key->ptr, val); } @@ -328,6 +328,7 @@ void shutdownCommand(redisClient *c) { void renameGenericCommand(redisClient *c, int nx) { robj *o; + time_t expire; /* To use the same key as src and dst is probably an error */ if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) { @@ -339,16 +340,18 @@ void renameGenericCommand(redisClient *c, int nx) { return; incrRefCount(o); + expire = getExpire(c->db,c->argv[1]); if (lookupKeyWrite(c->db,c->argv[2]) != NULL) { if (nx) { decrRefCount(o); addReply(c,shared.czero); return; } - dbOverwrite(c->db,c->argv[2],o); - } else { - dbAdd(c->db,c->argv[2],o); + /* Overwrite: delete the old key before creating the new one with the same name. */ + dbDelete(c->db,c->argv[2]); } + dbAdd(c->db,c->argv[2],o); + if (expire != -1) setExpire(c->db,c->argv[2],expire); dbDelete(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[2]); @@ -419,7 +422,7 @@ void moveCommand(redisClient *c) { int removeExpire(redisDb *db, robj *key) { /* An expire may only be removed if there is a corresponding entry in the * main dict. Otherwise, the key will never be freed. */ - redisAssert(dictFind(db->dict,key->ptr) != NULL); + redisAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL); return dictDelete(db->expires,key->ptr) == DICT_OK; } @@ -428,7 +431,7 @@ void setExpire(redisDb *db, robj *key, time_t when) { /* Reuse the sds from the main dict in the expire dict */ de = dictFind(db->dict,key->ptr); - redisAssert(de != NULL); + redisAssertWithInfo(NULL,key,de != NULL); dictReplace(db->expires,dictGetEntryKey(de),(void*)when); } @@ -443,7 +446,7 @@ time_t getExpire(redisDb *db, robj *key) { /* The entry was found in the expire dict, this means it should also * be present in the main dict (safety check). */ - redisAssert(dictFind(db->dict,key->ptr) != NULL); + redisAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL); return (time_t) dictGetEntryVal(de); } @@ -516,10 +519,24 @@ void expireGenericCommand(redisClient *c, robj *key, robj *param, long offset) { addReply(c,shared.czero); return; } - if (seconds <= 0 && !server.loading) { - if (dbDelete(c->db,key)) server.dirty++; - addReply(c, shared.cone); + /* EXPIRE with negative TTL, or EXPIREAT with a timestamp into the past + * should never be executed as a DEL when load the AOF or in the context + * of a slave instance. + * + * Instead we take the other branch of the IF statement setting an expire + * (possibly in the past) and wait for an explicit DEL from the master. */ + if (seconds <= 0 && !server.loading && !server.masterhost) { + robj *aux; + + redisAssertWithInfo(c,key,dbDelete(c->db,key)); + server.dirty++; + + /* Replicate/AOF this as an explicit DEL. */ + aux = createStringObject("DEL",3); + rewriteClientCommandVector(c,2,aux,key); + decrRefCount(aux); signalModifiedKey(c->db,key); + addReply(c, shared.cone); return; } else { time_t when = time(NULL)+seconds;