]> git.saurik.com Git - redis.git/blobdiff - src/t_string.c
Merge remote-tracking branch 'origin/unstable' into unstable
[redis.git] / src / t_string.c
index 2d7785ff3e33dde5d9f7bd9489048c23e816811f..2bd1646e305627ecab073893553a40f48444c2bf 100644 (file)
@@ -1,5 +1,5 @@
-#include <limits.h>
 #include "redis.h"
+#include <math.h> /* isnan(), isinf() */
 
 /*-----------------------------------------------------------------------------
  * String Commands
@@ -13,51 +13,47 @@ static int checkStringLength(redisClient *c, long long size) {
     return REDIS_OK;
 }
 
-void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire) {
-    int retval;
-    long seconds = 0; /* initialized to avoid an harmness warning */
+void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire, int unit) {
+    long long milliseconds = 0; /* initialized to avoid an harmness warning */
 
     if (expire) {
-        if (getLongFromObjectOrReply(c, expire, &seconds, NULL) != REDIS_OK)
+        if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
             return;
-        if (seconds <= 0) {
+        if (milliseconds <= 0) {
             addReplyError(c,"invalid expire time in SETEX");
             return;
         }
+        if (unit == UNIT_SECONDS) milliseconds *= 1000;
     }
 
-    retval = dbAdd(c->db,key,val);
-    if (retval == REDIS_ERR) {
-        if (!nx) {
-            dbReplace(c->db,key,val);
-            incrRefCount(val);
-        } else {
-            addReply(c,shared.czero);
-            return;
-        }
-    } else {
-        incrRefCount(val);
+    if (lookupKeyWrite(c->db,key) != NULL && nx) {
+        addReply(c,shared.czero);
+        return;
     }
-    signalModifiedKey(c->db,key);
+    setKey(c->db,key,val);
     server.dirty++;
-    removeExpire(c->db,key);
-    if (expire) setExpire(c->db,key,time(NULL)+seconds);
+    if (expire) setExpire(c->db,key,mstime()+milliseconds);
     addReply(c, nx ? shared.cone : shared.ok);
 }
 
 void setCommand(redisClient *c) {
     c->argv[2] = tryObjectEncoding(c->argv[2]);
-    setGenericCommand(c,0,c->argv[1],c->argv[2],NULL);
+    setGenericCommand(c,0,c->argv[1],c->argv[2],NULL,0);
 }
 
 void setnxCommand(redisClient *c) {
     c->argv[2] = tryObjectEncoding(c->argv[2]);
-    setGenericCommand(c,1,c->argv[1],c->argv[2],NULL);
+    setGenericCommand(c,1,c->argv[1],c->argv[2],NULL,0);
 }
 
 void setexCommand(redisClient *c) {
     c->argv[3] = tryObjectEncoding(c->argv[3]);
-    setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2]);
+    setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2],UNIT_SECONDS);
+}
+
+void psetexCommand(redisClient *c) {
+    c->argv[3] = tryObjectEncoding(c->argv[3]);
+    setGenericCommand(c,0,c->argv[1],c->argv[3],c->argv[2],UNIT_MILLISECONDS);
 }
 
 int getGenericCommand(redisClient *c) {
@@ -82,11 +78,8 @@ void getCommand(redisClient *c) {
 void getsetCommand(redisClient *c) {
     if (getGenericCommand(c) == REDIS_ERR) return;
     c->argv[2] = tryObjectEncoding(c->argv[2]);
-    dbReplace(c->db,c->argv[1],c->argv[2]);
-    incrRefCount(c->argv[2]);
-    signalModifiedKey(c->db,c->argv[1]);
+    setKey(c->db,c->argv[1],c->argv[2]);
     server.dirty++;
-    removeExpire(c->db,c->argv[1]);
 }
 
 static int getBitOffsetFromArgument(redisClient *c, robj *o, size_t *offset) {
@@ -139,7 +132,7 @@ void setbitCommand(redisClient *c) {
             robj *decoded = getDecodedObject(o);
             o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
             decrRefCount(decoded);
-            dbReplace(c->db,c->argv[1],o);
+            dbOverwrite(c->db,c->argv[1],o);
         }
     }
 
@@ -237,7 +230,7 @@ void setrangeCommand(redisClient *c) {
             robj *decoded = getDecodedObject(o);
             o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
             decrRefCount(decoded);
-            dbReplace(c->db,c->argv[1],o);
+            dbOverwrite(c->db,c->argv[1],o);
         }
     }
 
@@ -260,7 +253,7 @@ void getrangeCommand(redisClient *c) {
         return;
     if (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != REDIS_OK)
         return;
-    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
+    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptybulk)) == NULL ||
         checkType(c,o,REDIS_STRING)) return;
 
     if (o->encoding == REDIS_ENCODING_INT) {
@@ -281,7 +274,7 @@ void getrangeCommand(redisClient *c) {
     /* Precondition: end >= 0 && end < strlen, so the only condition where
      * nothing can be returned is: start > end. */
     if (start > end) {
-        addReply(c,shared.nullbulk);
+        addReply(c,shared.emptybulk);
     } else {
         addReplyBulkCBuffer(c,(char*)str+start,end-start+1);
     }
@@ -320,18 +313,15 @@ void msetGenericCommand(redisClient *c, int nx) {
                 busykeys++;
             }
         }
-    }
-    if (busykeys) {
-        addReply(c, shared.czero);
-        return;
+        if (busykeys) {
+            addReply(c, shared.czero);
+            return;
+        }
     }
 
     for (j = 1; j < c->argc; j += 2) {
         c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
-        dbReplace(c->db,c->argv[j],c->argv[j+1]);
-        incrRefCount(c->argv[j+1]);
-        removeExpire(c->db,c->argv[j]);
-        signalModifiedKey(c->db,c->argv[j]);
+        setKey(c->db,c->argv[j],c->argv[j+1]);
     }
     server.dirty += (c->argc-1)/2;
     addReply(c, nx ? shared.cone : shared.ok);
@@ -347,7 +337,7 @@ void msetnxCommand(redisClient *c) {
 
 void incrDecrCommand(redisClient *c, long long incr) {
     long long value, oldvalue;
-    robj *o;
+    robj *o, *new;
 
     o = lookupKeyWrite(c->db,c->argv[1]);
     if (o != NULL && checkType(c,o,REDIS_STRING)) return;
@@ -359,12 +349,15 @@ void incrDecrCommand(redisClient *c, long long incr) {
         addReplyError(c,"increment or decrement would overflow");
         return;
     }
-    o = createStringObjectFromLongLong(value);
-    dbReplace(c->db,c->argv[1],o);
+    new = createStringObjectFromLongLong(value);
+    if (o)
+        dbOverwrite(c->db,c->argv[1],new);
+    else
+        dbAdd(c->db,c->argv[1],new);
     signalModifiedKey(c->db,c->argv[1]);
     server.dirty++;
     addReply(c,shared.colon);
-    addReply(c,o);
+    addReply(c,new);
     addReply(c,shared.crlf);
 }
 
@@ -390,6 +383,39 @@ void decrbyCommand(redisClient *c) {
     incrDecrCommand(c,-incr);
 }
 
+void incrbyfloatCommand(redisClient *c) {
+    long double incr, value;
+    robj *o, *new, *aux;
+
+    o = lookupKeyWrite(c->db,c->argv[1]);
+    if (o != NULL && checkType(c,o,REDIS_STRING)) return;
+    if (getLongDoubleFromObjectOrReply(c,o,&value,NULL) != REDIS_OK ||
+        getLongDoubleFromObjectOrReply(c,c->argv[2],&incr,NULL) != REDIS_OK)
+        return;
+
+    value += incr;
+    if (isnan(value) || isinf(value)) {
+        addReplyError(c,"increment would produce NaN or Infinity");
+        return;
+    }
+    new = createStringObjectFromLongDouble(value);
+    if (o)
+        dbOverwrite(c->db,c->argv[1],new);
+    else
+        dbAdd(c->db,c->argv[1],new);
+    signalModifiedKey(c->db,c->argv[1]);
+    server.dirty++;
+    addReplyBulk(c,new);
+
+    /* Always replicate INCRBYFLOAT as a SET command with the final value
+     * in order to make sure that differences in float pricision or formatting
+     * will not create differences in replicas or after an AOF restart. */
+    aux = createStringObject("SET",3);
+    rewriteClientCommandArgument(c,0,aux);
+    decrRefCount(aux);
+    rewriteClientCommandArgument(c,2,new);
+}
+
 void appendCommand(redisClient *c) {
     size_t totlen;
     robj *o, *append;
@@ -417,7 +443,7 @@ void appendCommand(redisClient *c) {
             robj *decoded = getDecodedObject(o);
             o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
             decrRefCount(decoded);
-            dbReplace(c->db,c->argv[1],o);
+            dbOverwrite(c->db,c->argv[1],o);
         }
 
         /* Append the value */