]> git.saurik.com Git - redis.git/blobdiff - src/t_list.c
Fixed bug breaking rdbSaveMillisecondTime() in 32 bit systems. Thanks to @anydot...
[redis.git] / src / t_list.c
index d88277261650230c17eb510c82b8fc7e2e33ca71..21fd1c2f5f333bc0fc9f0f6aa6efb57aa45001c0 100644 (file)
@@ -198,7 +198,7 @@ void listTypeInsert(listTypeEntry *entry, robj *value, int where) {
 int listTypeEqual(listTypeEntry *entry, robj *o) {
     listTypeIterator *li = entry->li;
     if (li->encoding == REDIS_ENCODING_ZIPLIST) {
 int listTypeEqual(listTypeEntry *entry, robj *o) {
     listTypeIterator *li = entry->li;
     if (li->encoding == REDIS_ENCODING_ZIPLIST) {
-        redisAssert(o->encoding == REDIS_ENCODING_RAW);
+        redisAssertWithInfo(NULL,o,o->encoding == REDIS_ENCODING_RAW);
         return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
     } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
         return equalStringObjects(o,listNodeValue(entry->ln));
         return ziplistCompare(entry->zi,o->ptr,sdslen(o->ptr));
     } else if (li->encoding == REDIS_ENCODING_LINKEDLIST) {
         return equalStringObjects(o,listNodeValue(entry->ln));
@@ -235,7 +235,7 @@ void listTypeDelete(listTypeEntry *entry) {
 void listTypeConvert(robj *subject, int enc) {
     listTypeIterator *li;
     listTypeEntry entry;
 void listTypeConvert(robj *subject, int enc) {
     listTypeIterator *li;
     listTypeEntry entry;
-    redisAssert(subject->type == REDIS_LIST);
+    redisAssertWithInfo(NULL,subject,subject->type == REDIS_LIST);
 
     if (enc == REDIS_ENCODING_LINKEDLIST) {
         list *l = listCreate();
 
     if (enc == REDIS_ENCODING_LINKEDLIST) {
         list *l = listCreate();
@@ -310,7 +310,7 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
     if (refval != NULL) {
         /* Note: we expect refval to be string-encoded because it is *not* the
          * last argument of the multi-bulk LINSERT. */
     if (refval != NULL) {
         /* Note: we expect refval to be string-encoded because it is *not* the
          * last argument of the multi-bulk LINSERT. */
-        redisAssert(refval->encoding == REDIS_ENCODING_RAW);
+        redisAssertWithInfo(c,refval,refval->encoding == REDIS_ENCODING_RAW);
 
         /* We're not sure if this value can be inserted yet, but we cannot
          * convert the list inside the iterator. We don't want to loop over
 
         /* We're not sure if this value can be inserted yet, but we cannot
          * convert the list inside the iterator. We don't want to loop over
@@ -519,7 +519,12 @@ void lrangeCommand(redisClient *c) {
             p = ziplistNext(o->ptr,p);
         }
     } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
             p = ziplistNext(o->ptr,p);
         }
     } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
-        listNode *ln = listIndex(o->ptr,start);
+        listNode *ln;
+
+        /* If we are nearest to the end of the list, reach the element
+         * starting from tail and going backward, as it is faster. */
+        if (start > llen/2) start -= llen;
+        ln = listIndex(o->ptr,start);
 
         while(rangelen--) {
             addReplyBulk(c,ln->value);
 
         while(rangelen--) {
             addReplyBulk(c,ln->value);
@@ -643,7 +648,7 @@ void lremCommand(redisClient *c) {
 void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
     robj *aux;
 
 void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey, robj *dstobj, robj *value) {
     robj *aux;
 
-    if (!handleClientsWaitingListPush(c,dstkey,value)) {
+    if (!handleClientsWaitingListPush(origclient,dstkey,value)) {
         /* Create the list if the key does not exist */
         if (!dstobj) {
             dstobj = createZiplistObject();
         /* Create the list if the key does not exist */
         if (!dstobj) {
             dstobj = createZiplistObject();
@@ -653,10 +658,12 @@ void rpoplpushHandlePush(redisClient *origclient, redisClient *c, robj *dstkey,
         }
         listTypePush(dstobj,value,REDIS_HEAD);
         /* If we are pushing as a result of LPUSH against a key
         }
         listTypePush(dstobj,value,REDIS_HEAD);
         /* If we are pushing as a result of LPUSH against a key
-         * watched by BLPOPLPUSH, we need to rewrite the command vector.
-         * But if this is called directly by RPOPLPUSH (either directly
+         * watched by BRPOPLPUSH, we need to rewrite the command vector
+         * as an LPUSH.
+         *
+         * If this is called directly by RPOPLPUSH (either directly
          * or via a BRPOPLPUSH where the popped list exists)
          * or via a BRPOPLPUSH where the popped list exists)
-         * we should replicate the BRPOPLPUSH command itself. */
+         * we should replicate the RPOPLPUSH command itself. */
         if (c != origclient) {
             aux = createStringObject("LPUSH",5);
             rewriteClientCommandVector(origclient,3,aux,dstkey,value);
         if (c != origclient) {
             aux = createStringObject("LPUSH",5);
             rewriteClientCommandVector(origclient,3,aux,dstkey,value);
@@ -767,9 +774,9 @@ void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeout, robj
             l = listCreate();
             retval = dictAdd(c->db->blocking_keys,keys[j],l);
             incrRefCount(keys[j]);
             l = listCreate();
             retval = dictAdd(c->db->blocking_keys,keys[j],l);
             incrRefCount(keys[j]);
-            redisAssert(retval == DICT_OK);
+            redisAssertWithInfo(c,keys[j],retval == DICT_OK);
         } else {
         } else {
-            l = dictGetEntryVal(de);
+            l = dictGetVal(de);
         }
         listAddNodeTail(l,c);
     }
         }
         listAddNodeTail(l,c);
     }
@@ -784,13 +791,13 @@ void unblockClientWaitingData(redisClient *c) {
     list *l;
     int j;
 
     list *l;
     int j;
 
-    redisAssert(c->bpop.keys != NULL);
+    redisAssertWithInfo(c,NULL,c->bpop.keys != NULL);
     /* The client may wait for multiple keys, so unblock it for every key. */
     for (j = 0; j < c->bpop.count; j++) {
         /* Remove this client from the list of clients waiting for this key. */
         de = dictFind(c->db->blocking_keys,c->bpop.keys[j]);
     /* The client may wait for multiple keys, so unblock it for every key. */
     for (j = 0; j < c->bpop.count; j++) {
         /* Remove this client from the list of clients waiting for this key. */
         de = dictFind(c->db->blocking_keys,c->bpop.keys[j]);
-        redisAssert(de != NULL);
-        l = dictGetEntryVal(de);
+        redisAssertWithInfo(c,c->bpop.keys[j],de != NULL);
+        l = dictGetVal(de);
         listDelNode(l,listSearchKey(l,c));
         /* If the list is empty we need to remove it to avoid wasting memory */
         if (listLength(l) == 0)
         listDelNode(l,listSearchKey(l,c));
         /* If the list is empty we need to remove it to avoid wasting memory */
         if (listLength(l) == 0)
@@ -829,7 +836,7 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
 
     de = dictFind(c->db->blocking_keys,key);
     if (de == NULL) return 0;
 
     de = dictFind(c->db->blocking_keys,key);
     if (de == NULL) return 0;
-    clients = dictGetEntryVal(de);
+    clients = dictGetVal(de);
     numclients = listLength(clients);
 
     /* Try to handle the push as long as there are clients waiting for a push.
     numclients = listLength(clients);
 
     /* Try to handle the push as long as there are clients waiting for a push.
@@ -841,7 +848,7 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
      * this happens, it simply tries the next client waiting for a push. */
     while (numclients--) {
         ln = listFirst(clients);
      * this happens, it simply tries the next client waiting for a push. */
     while (numclients--) {
         ln = listFirst(clients);
-        redisAssert(ln != NULL);
+        redisAssertWithInfo(c,key,ln != NULL);
         receiver = ln->value;
         dstkey = receiver->bpop.target;
 
         receiver = ln->value;
         dstkey = receiver->bpop.target;
 
@@ -910,6 +917,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
                 if (listTypeLength(o) != 0) {
                     /* If the list contains elements fall back to the usual
                      * non-blocking POP operation */
                 if (listTypeLength(o) != 0) {
                     /* If the list contains elements fall back to the usual
                      * non-blocking POP operation */
+                    struct redisCommand *orig_cmd;
                     robj *argv[2], **orig_argv;
                     int orig_argc;
 
                     robj *argv[2], **orig_argv;
                     int orig_argc;
 
@@ -917,6 +925,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
                      * popGenericCommand() as the command takes a single key. */
                     orig_argv = c->argv;
                     orig_argc = c->argc;
                      * popGenericCommand() as the command takes a single key. */
                     orig_argv = c->argv;
                     orig_argc = c->argc;
+                    orig_cmd = c->cmd;
                     argv[1] = c->argv[j];
                     c->argv = argv;
                     c->argc = 2;
                     argv[1] = c->argv[j];
                     c->argv = argv;
                     c->argc = 2;
@@ -934,6 +943,7 @@ void blockingPopGenericCommand(redisClient *c, int where) {
                     /* Fix the client structure with the original stuff */
                     c->argv = orig_argv;
                     c->argc = orig_argc;
                     /* Fix the client structure with the original stuff */
                     c->argv = orig_argv;
                     c->argc = orig_argc;
+                    c->cmd = orig_cmd;
 
                     return;
                 }
 
                     return;
                 }
@@ -985,7 +995,7 @@ void brpoplpushCommand(redisClient *c) {
 
             /* The list exists and has elements, so
              * the regular rpoplpushCommand is executed. */
 
             /* The list exists and has elements, so
              * the regular rpoplpushCommand is executed. */
-            redisAssert(listTypeLength(key) > 0);
+            redisAssertWithInfo(c,key,listTypeLength(key) > 0);
             rpoplpushCommand(c);
         }
     }
             rpoplpushCommand(c);
         }
     }