]> git.saurik.com Git - redis.git/commitdiff
A first fix for SET key overwrite
authorantirez <antirez@gmail.com>
Tue, 5 Jan 2010 19:25:56 +0000 (14:25 -0500)
committerantirez <antirez@gmail.com>
Tue, 5 Jan 2010 19:25:56 +0000 (14:25 -0500)
redis.c

diff --git a/redis.c b/redis.c
index 1c0517e7f4d7556458e05dfc95ce9502970333bd..55a9ff9cdc1f2edcc53f96cf559c3448b8e630b7 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -469,6 +469,7 @@ static robj *getDecodedObject(robj *o);
 static int removeExpire(redisDb *db, robj *key);
 static int expireIfNeeded(redisDb *db, robj *key);
 static int deleteIfVolatile(redisDb *db, robj *key);
+static int deleteIfSwapped(redisDb *db, robj *key);
 static int deleteKey(redisDb *db, robj *key);
 static time_t getExpire(redisDb *db, robj *key);
 static int setExpire(redisDb *db, robj *key, time_t when);
@@ -3264,6 +3265,12 @@ static void setGenericCommand(redisClient *c, int nx) {
     retval = dictAdd(c->db->dict,c->argv[1],c->argv[2]);
     if (retval == DICT_ERR) {
         if (!nx) {
+            /* If the key is about a swapped value, we want a new key object
+             * to overwrite the old. So we delete the old key in the database.
+             * This will also make sure that swap pages about the old object
+             * will be marked as free. */
+            if (deleteIfSwapped(c->db,c->argv[1]))
+                incrRefCount(c->argv[1]);
             dictReplace(c->db->dict,c->argv[1],c->argv[2]);
             incrRefCount(c->argv[2]);
         } else {
@@ -7032,6 +7039,19 @@ static int vmCanSwapOut(void) {
     return (server.bgsavechildpid == -1 && server.bgrewritechildpid == -1);
 }
 
+/* Delete a key if swapped. Returns 1 if the key was found, was swapped
+ * and was deleted. Otherwise 0 is returned. */
+static int deleteIfSwapped(redisDb *db, robj *key) {
+    dictEntry *de;
+    robj *foundkey;
+
+    if ((de = dictFind(db->dict,key)) == NULL) return 0;
+    foundkey = dictGetEntryKey(de);
+    if (foundkey->storage == REDIS_VM_MEMORY) return 0;
+    deleteKey(db,key);
+    return 1;
+}
+
 /* ================================= Debugging ============================== */
 
 static void debugCommand(redisClient *c) {