]> git.saurik.com Git - redis.git/commitdiff
Merged ZREVRANK from Pietern
authorantirez <antirez@gmail.com>
Tue, 9 Mar 2010 15:19:33 +0000 (16:19 +0100)
committerantirez <antirez@gmail.com>
Tue, 9 Mar 2010 15:19:33 +0000 (16:19 +0100)
1  2 
redis.c

diff --combined redis.c
index 3c1408f7fd95296de693bf18ee73d9fa906b675e,c882694dd34d27481c921b1e48cca488c73560b2..c1777c761931b29a2e56d85e4b810b253f8ffc40
+++ b/redis.c
  #define APPENDFSYNC_ALWAYS 1
  #define APPENDFSYNC_EVERYSEC 2
  
 +/* Hashes related defaults */
 +#define REDIS_HASH_MAX_ZIPMAP_ENTRIES 64
 +#define REDIS_HASH_MAX_ZIPMAP_VALUE 512
 +
  /* We can print the stacktrace, so our assert is defined this way: */
  #define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
  static void _redisAssert(char *estr, char *file, int line);
@@@ -395,9 -391,6 +395,9 @@@ struct redisServer 
      off_t vm_page_size;
      off_t vm_pages;
      unsigned long long vm_max_memory;
 +    /* Hashes config */
 +    size_t hash_max_zipmap_entries;
 +    size_t hash_max_zipmap_value;
      /* Virtual memory state */
      FILE *vm_fp;
      int vm_fd;
@@@ -590,7 -583,6 +590,7 @@@ static void readQueryFromClient(aeEvent
  static struct redisCommand *lookupCommand(char *name);
  static void call(redisClient *c, struct redisCommand *cmd);
  static void resetClient(redisClient *c);
 +static void convertToRealHash(robj *o);
  
  static void authCommand(redisClient *c);
  static void pingCommand(redisClient *c);
@@@ -674,6 -666,7 +674,7 @@@ static void brpopCommand(redisClient *c
  static void appendCommand(redisClient *c);
  static void substrCommand(redisClient *c);
  static void zrankCommand(redisClient *c);
+ static void zrevrankCommand(redisClient *c);
  static void hsetCommand(redisClient *c);
  static void hgetCommand(redisClient *c);
  
@@@ -730,6 -723,7 +731,7 @@@ static struct redisCommand cmdTable[] 
      {"zcard",zcardCommand,2,REDIS_CMD_INLINE,1,1,1},
      {"zscore",zscoreCommand,3,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,1,1,1},
      {"zrank",zrankCommand,3,REDIS_CMD_INLINE,1,1,1},
+     {"zrevrank",zrevrankCommand,3,REDIS_CMD_INLINE,1,1,1},
      {"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,1,1,1},
      {"hget",hgetCommand,3,REDIS_CMD_BULK,1,1,1},
      {"incrby",incrbyCommand,3,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,1,1,1},
@@@ -1473,8 -1467,6 +1475,8 @@@ static void initServerConfig() 
      server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */
      server.vm_max_threads = 4;
      server.vm_blocked_clients = 0;
 +    server.hash_max_zipmap_entries = REDIS_HASH_MAX_ZIPMAP_ENTRIES;
 +    server.hash_max_zipmap_value = REDIS_HASH_MAX_ZIPMAP_VALUE;
  
      resetServerSaveParams();
  
@@@ -1735,12 -1727,6 +1737,12 @@@ static void loadServerConfig(char *file
              server.vm_pages = strtoll(argv[1], NULL, 10);
          } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
              server.vm_max_threads = strtoll(argv[1], NULL, 10);
 +        } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2){
 +            server.hash_max_zipmap_entries = strtol(argv[1], NULL, 10);
 +        } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2){
 +            server.hash_max_zipmap_value = strtol(argv[1], NULL, 10);
 +        } else if (!strcasecmp(argv[0],"vm-max-threads") && argc == 2) {
 +            server.vm_max_threads = strtoll(argv[1], NULL, 10);
          } else {
              err = "Bad directive or wrong number of arguments"; goto loaderr;
          }
@@@ -2619,17 -2605,7 +2621,17 @@@ static void freeZsetObject(robj *o) 
  }
  
  static void freeHashObject(robj *o) {
 -    dictRelease((dict*) o->ptr);
 +    switch (o->encoding) {
 +    case REDIS_ENCODING_HT:
 +        dictRelease((dict*) o->ptr);
 +        break;
 +    case REDIS_ENCODING_ZIPMAP:
 +        zfree(o->ptr);
 +        break;
 +    default:
 +        redisAssert(0);
 +        break;
 +    }
  }
  
  static void incrRefCount(robj *o) {
@@@ -2934,7 -2910,7 +2936,7 @@@ static int rdbSaveLen(FILE *fp, uint32_
  /* String objects in the form "2391" "-100" without any space and with a
   * range of values that can fit in an 8, 16 or 32 bit signed value can be
   * encoded as integers to save space */
 -static int rdbTryIntegerEncoding(sds s, unsigned char *enc) {
 +static int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
      long long value;
      char *endptr, buf[32];
  
  
      /* If the number converted back into a string is not identical
       * then it's not possible to encode the string as integer */
 -    if (strlen(buf) != sdslen(s) || memcmp(buf,s,sdslen(s))) return 0;
 +    if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
  
      /* Finally check if it fits in our ranges */
      if (value >= -(1<<7) && value <= (1<<7)-1) {
      }
  }
  
 -static int rdbSaveLzfStringObject(FILE *fp, robj *obj) {
 -    unsigned int comprlen, outlen;
 +static int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
 +    size_t comprlen, outlen;
      unsigned char byte;
      void *out;
  
      /* We require at least four bytes compression for this to be worth it */
 -    outlen = sdslen(obj->ptr)-4;
 -    if (outlen <= 0) return 0;
 +    if (len <= 4) return 0;
 +    outlen = len-4;
      if ((out = zmalloc(outlen+1)) == NULL) return 0;
 -    comprlen = lzf_compress(obj->ptr, sdslen(obj->ptr), out, outlen);
 +    comprlen = lzf_compress(s, len, out, outlen);
      if (comprlen == 0) {
          zfree(out);
          return 0;
      byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
      if (fwrite(&byte,1,1,fp) == 0) goto writeerr;
      if (rdbSaveLen(fp,comprlen) == -1) goto writeerr;
 -    if (rdbSaveLen(fp,sdslen(obj->ptr)) == -1) goto writeerr;
 +    if (rdbSaveLen(fp,len) == -1) goto writeerr;
      if (fwrite(out,comprlen,1,fp) == 0) goto writeerr;
      zfree(out);
      return comprlen;
@@@ -2999,13 -2975,16 +3001,13 @@@ writeerr
  
  /* Save a string objet as [len][data] on disk. If the object is a string
   * representation of an integer value we try to safe it in a special form */
 -static int rdbSaveStringObjectRaw(FILE *fp, robj *obj) {
 -    size_t len;
 +static int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
      int enclen;
  
 -    len = sdslen(obj->ptr);
 -
      /* Try integer encoding */
      if (len <= 11) {
          unsigned char buf[5];
 -        if ((enclen = rdbTryIntegerEncoding(obj->ptr,buf)) > 0) {
 +        if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
              if (fwrite(buf,enclen,1,fp) == 0) return -1;
              return 0;
          }
      if (server.rdbcompression && len > 20) {
          int retval;
  
 -        retval = rdbSaveLzfStringObject(fp,obj);
 +        retval = rdbSaveLzfStringObject(fp,s,len);
          if (retval == -1) return -1;
          if (retval > 0) return 0;
          /* retval == 0 means data can't be compressed, save the old way */
  
      /* Store verbatim */
      if (rdbSaveLen(fp,len) == -1) return -1;
 -    if (len && fwrite(obj->ptr,len,1,fp) == 0) return -1;
 +    if (len && fwrite(s,len,1,fp) == 0) return -1;
      return 0;
  }
  
@@@ -3039,10 -3018,10 +3041,10 @@@ static int rdbSaveStringObject(FILE *fp
       * this in order to avoid bugs) */
      if (obj->encoding != REDIS_ENCODING_RAW) {
          obj = getDecodedObject(obj);
 -        retval = rdbSaveStringObjectRaw(fp,obj);
 +        retval = rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
          decrRefCount(obj);
      } else {
 -        retval = rdbSaveStringObjectRaw(fp,obj);
 +        retval = rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
      }
      return retval;
  }
@@@ -3120,33 -3099,6 +3122,33 @@@ static int rdbSaveObject(FILE *fp, rob
              if (rdbSaveDoubleValue(fp,*score) == -1) return -1;
          }
          dictReleaseIterator(di);
 +    } else if (o->type == REDIS_HASH) {
 +        /* Save a hash value */
 +        if (o->encoding == REDIS_ENCODING_ZIPMAP) {
 +            unsigned char *p = zipmapRewind(o->ptr);
 +            unsigned int count = zipmapLen(o->ptr);
 +            unsigned char *key, *val;
 +            unsigned int klen, vlen;
 +
 +            if (rdbSaveLen(fp,count) == -1) return -1;
 +            while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
 +                if (rdbSaveRawString(fp,key,klen) == -1) return -1;
 +                if (rdbSaveRawString(fp,val,vlen) == -1) return -1;
 +            }
 +        } else {
 +            dictIterator *di = dictGetIterator(o->ptr);
 +            dictEntry *de;
 +
 +            if (rdbSaveLen(fp,dictSize((dict*)o->ptr)) == -1) return -1;
 +            while((de = dictNext(di)) != NULL) {
 +                robj *key = dictGetEntryKey(de);
 +                robj *val = dictGetEntryVal(de);
 +
 +                if (rdbSaveStringObject(fp,key) == -1) return -1;
 +                if (rdbSaveStringObject(fp,val) == -1) return -1;
 +            }
 +            dictReleaseIterator(di);
 +        }
      } else {
          redisAssert(0 != 0);
      }
@@@ -3471,7 -3423,7 +3473,7 @@@ static robj *rdbLoadObject(int type, FI
          }
      } else if (type == REDIS_ZSET) {
          /* Read list/set value */
 -        uint32_t zsetlen;
 +        size_t zsetlen;
          zset *zs;
  
          if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
              zslInsert(zs->zsl,*score,ele);
              incrRefCount(ele); /* added to skiplist */
          }
 +    } else if (type == REDIS_HASH) {
 +        size_t hashlen;
 +
 +        if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
 +        o = createHashObject();
 +        /* Too many entries? Use an hash table. */
 +        if (hashlen > server.hash_max_zipmap_entries)
 +            convertToRealHash(o);
 +        /* Load every key/value, then set it into the zipmap or hash
 +         * table, as needed. */
 +        while(hashlen--) {
 +            robj *key, *val;
 +
 +            if ((key = rdbLoadStringObject(fp)) == NULL) return NULL;
 +            if ((val = rdbLoadStringObject(fp)) == NULL) return NULL;
 +            /* If we are using a zipmap and there are too big values
 +             * the object is converted to real hash table encoding. */
 +            if (o->encoding != REDIS_ENCODING_HT &&
 +               (sdslen(key->ptr) > server.hash_max_zipmap_value ||
 +                sdslen(val->ptr) > server.hash_max_zipmap_value))
 +            {
 +                    convertToRealHash(o);
 +            }
 +
 +            if (o->encoding == REDIS_ENCODING_ZIPMAP) {
 +                unsigned char *zm = o->ptr;
 +
 +                zm = zipmapSet(zm,key->ptr,sdslen(key->ptr),
 +                                  val->ptr,sdslen(val->ptr),NULL);
 +                o->ptr = zm;
 +                decrRefCount(key);
 +                decrRefCount(val);
 +            } else {
 +                tryObjectEncoding(key);
 +                tryObjectEncoding(val);
 +                dictAdd((dict*)o->ptr,key,val);
 +                incrRefCount(key);
 +                incrRefCount(val);
 +            }
 +        }
      } else {
          redisAssert(0 != 0);
      }
@@@ -4036,8 -3948,7 +4038,8 @@@ static void typeCommand(redisClient *c
          case REDIS_LIST: type = "+list"; break;
          case REDIS_SET: type = "+set"; break;
          case REDIS_ZSET: type = "+zset"; break;
 -        default: type = "unknown"; break;
 +        case REDIS_HASH: type = "+hash"; break;
 +        default: type = "+unknown"; break;
          }
      }
      addReplySds(c,sdsnew(type));
@@@ -5637,7 -5548,7 +5639,7 @@@ static void zscoreCommand(redisClient *
      }
  }
  
- static void zrankCommand(redisClient *c) {
+ static void zrankGenericCommand(redisClient *c, int reverse) {
      robj *o;
      o = lookupKeyRead(c->db,c->argv[1]);
      if (o == NULL) {
          double *score = dictGetEntryVal(de);
          rank = zslGetRank(zsl, *score, c->argv[2]);
          if (rank) {
-             addReplyLong(c, rank-1);
+             if (reverse) {
+                 addReplyLong(c, zsl->length - rank);
+             } else {
+                 addReplyLong(c, rank-1);
+             }
          } else {
              addReply(c,shared.nullbulk);
          }
      }
  }
  
 -/* ==================================== Hash ================================ */
+ static void zrankCommand(redisClient *c) {
+     zrankGenericCommand(c, 0);
+ }
+ static void zrevrankCommand(redisClient *c) {
+     zrankGenericCommand(c, 1);
+ }
 +/* =================================== Hashes =============================== */
  static void hsetCommand(redisClient *c) {
      int update = 0;
      robj *o = lookupKeyWrite(c->db,c->argv[1]);
      }
      if (o->encoding == REDIS_ENCODING_ZIPMAP) {
          unsigned char *zm = o->ptr;
 +        robj *valobj = getDecodedObject(c->argv[3]);
  
          zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
 -            c->argv[3]->ptr,sdslen(c->argv[3]->ptr),&update);
 +            valobj->ptr,sdslen(valobj->ptr),&update);
 +        decrRefCount(valobj);
 +        o->ptr = zm;
      } else {
          if (dictAdd(o->ptr,c->argv[2],c->argv[3]) == DICT_OK) {
              incrRefCount(c->argv[2]);
@@@ -5741,27 -5661,6 +5755,27 @@@ static void hgetCommand(redisClient *c
      }
  }
  
 +static void convertToRealHash(robj *o) {
 +    unsigned char *key, *val, *p, *zm = o->ptr;
 +    unsigned int klen, vlen;
 +    dict *dict = dictCreate(&hashDictType,NULL);
 +
 +    assert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
 +    p = zipmapRewind(zm);
 +    while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
 +        robj *keyobj, *valobj;
 +
 +        keyobj = createStringObject((char*)key,klen);
 +        valobj = createStringObject((char*)val,vlen);
 +        tryObjectEncoding(keyobj);
 +        tryObjectEncoding(valobj);
 +        dictAdd(dict,keyobj,valobj);
 +    }
 +    o->encoding = REDIS_ENCODING_HT;
 +    o->ptr = dict;
 +    zfree(zm);
 +}
 +
  /* ========================= Non type-specific commands  ==================== */
  
  static void flushdbCommand(redisClient *c) {