]> git.saurik.com Git - redis.git/commitdiff
merged memory reduction patch
authorPieter Noordhuis <pcnoordhuis@gmail.com>
Thu, 4 Mar 2010 15:35:57 +0000 (16:35 +0100)
committerPieter Noordhuis <pcnoordhuis@gmail.com>
Thu, 4 Mar 2010 15:35:57 +0000 (16:35 +0100)
1  2 
redis.c

diff --combined redis.c
index bff1cdfc548adf64050f4540822b548fcabc23c2,0353940e2914d10510180f388ebfd5d5c903bd09..4f7d3efcd0e2e57627c97e65bf5d983e0c449371
+++ b/redis.c
@@@ -659,7 -659,6 +659,7 @@@ static void discardCommand(redisClient 
  static void blpopCommand(redisClient *c);
  static void brpopCommand(redisClient *c);
  static void appendCommand(redisClient *c);
 +static void substrCommand(redisClient *c);
  static void zrankCommand(redisClient *c);
  
  /*================================= Globals ================================= */
@@@ -671,7 -670,6 +671,7 @@@ static struct redisCommand cmdTable[] 
      {"set",setCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,0,0,0},
      {"setnx",setnxCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,0,0,0},
      {"append",appendCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,1,1,1},
 +    {"substr",substrCommand,4,REDIS_CMD_INLINE,1,1,1},
      {"del",delCommand,-2,REDIS_CMD_INLINE,0,0,0},
      {"exists",existsCommand,2,REDIS_CMD_INLINE,1,1,1},
      {"incr",incrCommand,2,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,1,1,1},
@@@ -3766,50 -3764,6 +3766,50 @@@ static void appendCommand(redisClient *
      addReplySds(c,sdscatprintf(sdsempty(),":%lu\r\n",(unsigned long)totlen));
  }
  
 +static void substrCommand(redisClient *c) {
 +    robj *o;
 +    long start = atoi(c->argv[2]->ptr);
 +    long end = atoi(c->argv[3]->ptr);
 +
 +    o = lookupKeyRead(c->db,c->argv[1]);
 +    if (o == NULL) {
 +        addReply(c,shared.nullbulk);
 +    } else {
 +        if (o->type != REDIS_STRING) {
 +            addReply(c,shared.wrongtypeerr);
 +        } else {
 +            size_t rangelen, strlen;
 +            sds range;
 +
 +            o = getDecodedObject(o);
 +            strlen = sdslen(o->ptr);
 +
 +            /* convert negative indexes */
 +            if (start < 0) start = strlen+start;
 +            if (end < 0) end = strlen+end;
 +            if (start < 0) start = 0;
 +            if (end < 0) end = 0;
 +
 +            /* indexes sanity checks */
 +            if (start > end || (size_t)start >= strlen) {
 +                /* Out of range start or start > end result in null reply */
 +                addReply(c,shared.nullbulk);
 +                decrRefCount(o);
 +                return;
 +            }
 +            if ((size_t)end >= strlen) end = strlen-1;
 +            rangelen = (end-start)+1;
 +
 +            /* Return the result */
 +            addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n",rangelen));
 +            range = sdsnewlen((char*)o->ptr+start,rangelen);
 +            addReplySds(c,range);
 +            addReply(c,shared.crlf);
 +            decrRefCount(o);
 +        }
 +    }
 +}
 +
  /* ========================= Type agnostic commands ========================= */
  
  static void delCommand(redisClient *c) {
@@@ -4844,7 -4798,8 +4844,8 @@@ static zskiplistNode *zslCreateNode(in
      zskiplistNode *zn = zmalloc(sizeof(*zn));
  
      zn->forward = zmalloc(sizeof(zskiplistNode*) * level);
-     zn->span = zmalloc(sizeof(unsigned int) * level);
+     if (level > 0)
+         zn->span = zmalloc(sizeof(unsigned int) * (level - 1));
      zn->score = score;
      zn->obj = obj;
      return zn;
@@@ -4897,19 -4852,23 +4898,19 @@@ static int zslRandomLevel(void) 
  
  static void zslInsert(zskiplist *zsl, double score, robj *obj) {
      zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
-     unsigned int span[ZSKIPLIST_MAXLEVEL];
+     unsigned int rank[ZSKIPLIST_MAXLEVEL];
      int i, level;
  
      x = zsl->header;
      for (i = zsl->level-1; i >= 0; i--) {
-         /* store span that is crossed to reach the insert position */
-         span[i] = i == (zsl->level-1) ? 0 : span[i+1];
+         /* store rank that is crossed to reach the insert position */
+         rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
  
          while (x->forward[i] &&
              (x->forward[i]->score < score ||
                  (x->forward[i]->score == score &&
                  compareStringObjects(x->forward[i]->obj,obj) < 0))) {
-             span[i] += x->span[i];
 -            if (i > 0) {
 -                rank[i] += x->span[i-1];
 -            } else {
 -                rank[i]++;
 -            }
++            rank[i] += i > 0 ? x->span[i-1] : 1;
              x = x->forward[i];
          }
          update[i] = x;
      level = zslRandomLevel();
      if (level > zsl->level) {
          for (i = zsl->level; i < level; i++) {
-             span[i] = 0;
+             rank[i] = 0;
              update[i] = zsl->header;
-             update[i]->span[i] = zsl->length;
+             update[i]->span[i-1] = zsl->length;
          }
          zsl->level = level;
      }
          update[i]->forward[i] = x;
  
          /* update span covered by update[i] as x is inserted here */
-         x->span[i] = update[i]->span[i] - (span[0] - span[i]);
-         update[i]->span[i] = (span[0] - span[i]) + 1;
+         if (i > 0) {
+             x->span[i-1] = update[i]->span[i-1] - (rank[0] - rank[i]);
+             update[i]->span[i-1] = (rank[0] - rank[i]) + 1;
+         }
      }
  
      /* increment span for untouched levels */
      for (i = level; i < zsl->level; i++) {
-         update[i]->span[i]++;
+         update[i]->span[i-1]++;
      }
  
      x->backward = (update[0] == zsl->header) ? NULL : update[0];
@@@ -4970,10 -4931,14 +4973,14 @@@ static int zslDelete(zskiplist *zsl, do
      if (x && score == x->score && compareStringObjects(x->obj,obj) == 0) {
          for (i = 0; i < zsl->level; i++) {
              if (update[i]->forward[i] == x) {
-                 update[i]->span[i] += x->span[i] - 1;
+                 if (i > 0) {
+                     update[i]->span[i-1] += x->span[i-1] - 1;
+                 }
                  update[i]->forward[i] = x->forward[i];
              } else {
-                 update[i]->span[i] -= 1;
+                 /* invariant: i > 0, because update[0]->forward[0]
+                  * is always equal to x */
+                 update[i]->span[i-1] -= 1;
              }
          }
          if (x->forward[0]) {
@@@ -5015,10 -4980,14 +5022,14 @@@ static unsigned long zslDeleteRange(zsk
  
          for (i = 0; i < zsl->level; i++) {
              if (update[i]->forward[i] == x) {
-                 update[i]->span[i] += x->span[i] - 1;
+                 if (i > 0) {
+                     update[i]->span[i-1] += x->span[i-1] - 1;
+                 }
                  update[i]->forward[i] = x->forward[i];
              } else {
-                 update[i]->span[i] -= 1;
+                 /* invariant: i > 0, because update[0]->forward[0]
+                  * is always equal to x */
+                 update[i]->span[i-1] -= 1;
              }
          }
          if (x->forward[0]) {
@@@ -5054,53 -5023,6 +5065,53 @@@ static zskiplistNode *zslFirstWithScore
      return x->forward[0];
  }
  
-             rank += x->span[i];
 +/* Find the rank for an element by both score and key.
 + * Returns 0 when the element cannot be found, rank otherwise.
 + * Note that the rank is 1-based due to the span of zsl->header to the
 + * first element. */
 +static unsigned long zslGetRank(zskiplist *zsl, double score, robj *o) {
 +    zskiplistNode *x;
 +    unsigned long rank = 0;
 +    int i;
 +
 +    x = zsl->header;
 +    for (i = zsl->level-1; i >= 0; i--) {
 +        while (x->forward[i] &&
 +            (x->forward[i]->score < score ||
 +                (x->forward[i]->score == score &&
 +                compareStringObjects(x->forward[i]->obj,o) <= 0))) {
-         while (x->forward[i] && (traversed + x->span[i]) <= rank) {
-             traversed += x->span[i];
++            rank += i > 0 ? x->span[i-1] : 1;
 +            x = x->forward[i];
 +        }
 +
 +        /* x might be equal to zsl->header, so test if obj is non-NULL */
 +        if (x->obj && compareStringObjects(x->obj,o) == 0) {
 +            return rank;
 +        }
 +    }
 +    return 0;
 +}
 +
 +/* Finds an element by its rank. The rank argument needs to be 1-based. */
 +zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) {
 +    zskiplistNode *x;
 +    unsigned long traversed = 0;
 +    int i;
 +
 +    x = zsl->header;
 +    for (i = zsl->level-1; i >= 0; i--) {
++        while (x->forward[i] && (traversed + (i > 0 ? x->span[i-1] : 1)) <= rank) {
++            traversed += i > 0 ? x->span[i-1] : 1;
 +            x = x->forward[i];
 +        }
 +
 +        if (traversed == rank) {
 +            return x;
 +        }
 +    }
 +    return NULL;
 +}
 +
  /* The actual Z-commands implementations */
  
  /* This generic command implements both ZADD and ZINCRBY.
@@@ -5300,15 -5222,17 +5311,15 @@@ static void zrangeGenericCommand(redisC
              if (end >= llen) end = llen-1;
              rangelen = (end-start)+1;
  
 -            /* Return the result in form of a multi-bulk reply */
 +            /* check if starting point is trivial, before searching
 +             * the element in log(N) time */
              if (reverse) {
 -                ln = zsl->tail;
 -                while (start--)
 -                    ln = ln->backward;
 +                ln = start == 0 ? zsl->tail : zslGetElementByRank(zsl, llen - start);
              } else {
 -                ln = zsl->header->forward[0];
 -                while (start--)
 -                    ln = ln->forward[0];
 +                ln = start == 0 ? zsl->header->forward[0] : zslGetElementByRank(zsl, start + 1);
              }
  
 +            /* Return the result in form of a multi-bulk reply */
              addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",
                  withscores ? (rangelen*2) : rangelen));
              for (j = 0; j < rangelen; j++) {
@@@ -5512,26 -5436,43 +5523,26 @@@ static void zrankCommand(redisClient *c
      }
      if (o->type != REDIS_ZSET) {
          addReply(c,shared.wrongtypeerr);
 -        return;
 -    }
 -
 -    zset *zs = o->ptr;
 -    zskiplist *zsl = zs->zsl;
 -    dictEntry *de = dictFind(zs->dict,c->argv[2]);
 -    if (!de) {
 -        addReply(c,shared.nullbulk);
 -        return;
 -    }
 -
 -    double *score = dictGetEntryVal(de);
 -    zskiplistNode *x;
 -    unsigned int rank = 0;
 -    int i;
 +    } else {
 +        zset *zs = o->ptr;
 +        zskiplist *zsl = zs->zsl;
 +        dictEntry *de;
 +        unsigned long rank;
  
 -    x = zsl->header;
 -    for (i = zsl->level-1; i >= 0; i--) {
 -        while (x->forward[i] &&
 -            (x->forward[i]->score < *score ||
 -                (x->forward[i]->score == *score &&
 -                compareStringObjects(x->forward[i]->obj,c->argv[2]) < 0))) {
 -            if (i > 0) {
 -                rank += x->span[i-1];
 -            } else {
 -                rank++;
 -            }
 -            x = x->forward[i];
 +        de = dictFind(zs->dict,c->argv[2]);
 +        if (!de) {
 +            addReply(c,shared.nullbulk);
 +            return;
          }
  
 -        if (x->forward[i] && compareStringObjects(x->forward[i]->obj,c->argv[2]) == 0) {
 -            addReplyLong(c, rank);
 -            return;
 +        double *score = dictGetEntryVal(de);
 +        rank = zslGetRank(zsl, *score, c->argv[2]);
 +        if (rank) {
 +            addReplyLong(c, rank-1);
 +        } else {
 +            addReply(c,shared.nullbulk);
          }
      }
 -
 -    addReply(c,shared.nullbulk);
  }
  
  /* ========================= Non type-specific commands  ==================== */