X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/5574b53eae1743cca9eed5a9dd25bf418c974701..4468ba231785fe9fda26f2d05181f91342d91c2d:/src/object.c diff --git a/src/object.c b/src/object.c index d74fc965..c2b89709 100644 --- a/src/object.c +++ b/src/object.c @@ -1,5 +1,36 @@ +/* Redis Object implementation. + * + * Copyright (c) 2009-2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + #include "redis.h" #include +#include robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); @@ -8,18 +39,8 @@ robj *createObject(int type, void *ptr) { o->ptr = ptr; o->refcount = 1; - /* Set the LRU to the current lruclock (minutes resolution). - * We do this regardless of the fact VM is active as LRU is also - * used for the maxmemory directive when Redis is used as cache. - * - * Note that this code may run in the context of an I/O thread - * and accessing server.lruclock in theory is an error - * (no locks). But in practice this is safe, and even if we read - * garbage Redis will not fail. */ + /* Set the LRU to the current lruclock (minutes resolution). */ o->lru = server.lruclock; - /* The following is only needed if VM is active, but since the conditional - * is probably more costly than initializing the field it's better to - * have every field properly initialized anyway. */ return o; } @@ -55,7 +76,16 @@ robj *createStringObjectFromLongDouble(long double value) { * that is "non surprising" for the user (that is, most small decimal * numbers will be represented in a way that when converted back into * a string are exactly the same as what the user typed.) */ - len = snprintf(buf,sizeof(buf),"%.17Lg", value); + len = snprintf(buf,sizeof(buf),"%.17Lf", value); + /* Now remove trailing zeroes after the '.' */ + if (strchr(buf,'.') != NULL) { + char *p = buf+len-1; + while(*p == '0') { + p--; + len--; + } + if (*p == '.') len--; + } return createStringObject(buf,len); } @@ -94,12 +124,9 @@ robj *createIntsetObject(void) { } robj *createHashObject(void) { - /* All the Hashes start as zipmaps. Will be automatically converted - * into hash tables if there are enough elements or big elements - * inside. */ - unsigned char *zm = zipmapNew(); - robj *o = createObject(REDIS_HASH,zm); - o->encoding = REDIS_ENCODING_ZIPMAP; + unsigned char *zl = ziplistNew(); + robj *o = createObject(REDIS_HASH, zl); + o->encoding = REDIS_ENCODING_ZIPLIST; return o; } @@ -175,7 +202,7 @@ void freeHashObject(robj *o) { case REDIS_ENCODING_HT: dictRelease((dict*) o->ptr); break; - case REDIS_ENCODING_ZIPMAP: + case REDIS_ENCODING_ZIPLIST: zfree(o->ptr); break; default: @@ -263,9 +290,7 @@ robj *tryObjectEncoding(robj *o) { /* Ok, this object can be encoded... * - * Can I use a shared object? Only if the object is inside a given - * range and if the back end in use is in-memory. For disk store every - * object in memory used as value should be independent. + * Can I use a shared object? Only if the object is inside a given range * * Note that we also avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU @@ -367,7 +392,8 @@ int getDoubleFromObject(robj *o, double *target) { if (o->encoding == REDIS_ENCODING_RAW) { errno = 0; value = strtod(o->ptr, &eptr); - if (eptr[0] != '\0' || errno == ERANGE || isnan(value)) + if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || + errno == ERANGE || isnan(value)) return REDIS_ERR; } else if (o->encoding == REDIS_ENCODING_INT) { value = (long)o->ptr; @@ -375,7 +401,6 @@ int getDoubleFromObject(robj *o, double *target) { redisPanic("Unknown string encoding"); } } - *target = value; return REDIS_OK; } @@ -390,7 +415,6 @@ int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const ch } return REDIS_ERR; } - *target = value; return REDIS_OK; } @@ -406,7 +430,8 @@ int getLongDoubleFromObject(robj *o, long double *target) { if (o->encoding == REDIS_ENCODING_RAW) { errno = 0; value = strtold(o->ptr, &eptr); - if (eptr[0] != '\0' || errno == ERANGE || isnan(value)) + if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || + errno == ERANGE || isnan(value)) return REDIS_ERR; } else if (o->encoding == REDIS_ENCODING_INT) { value = (long)o->ptr; @@ -428,7 +453,6 @@ int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, } return REDIS_ERR; } - *target = value; return REDIS_OK; } @@ -442,9 +466,10 @@ int getLongLongFromObject(robj *o, long long *target) { } else { redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); if (o->encoding == REDIS_ENCODING_RAW) { + errno = 0; value = strtoll(o->ptr, &eptr, 10); - if (eptr[0] != '\0') return REDIS_ERR; - if (errno == ERANGE && (value == LLONG_MIN || value == LLONG_MAX)) + if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || + errno == ERANGE) return REDIS_ERR; } else if (o->encoding == REDIS_ENCODING_INT) { value = (long)o->ptr; @@ -452,7 +477,6 @@ int getLongLongFromObject(robj *o, long long *target) { redisPanic("Unknown string encoding"); } } - if (target) *target = value; return REDIS_OK; } @@ -467,7 +491,6 @@ int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, con } return REDIS_ERR; } - *target = value; return REDIS_OK; } @@ -484,7 +507,6 @@ int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char * } return REDIS_ERR; } - *target = value; return REDIS_OK; } @@ -494,7 +516,6 @@ char *strEncoding(int encoding) { case REDIS_ENCODING_RAW: return "raw"; case REDIS_ENCODING_INT: return "int"; case REDIS_ENCODING_HT: return "hashtable"; - case REDIS_ENCODING_ZIPMAP: return "zipmap"; case REDIS_ENCODING_LINKEDLIST: return "linkedlist"; case REDIS_ENCODING_ZIPLIST: return "ziplist"; case REDIS_ENCODING_INTSET: return "intset";