diff --git a/src/geo.c b/src/geo.c index 4ebd678b5..ac25a20c6 100644 --- a/src/geo.c +++ b/src/geo.c @@ -490,7 +490,7 @@ void geoaddCommand(client *c) { GeoHashBits hash; geohashEncodeWGS84(xy[0], xy[1], GEO_STEP_MAX, &hash); GeoHashFix52Bits bits = geohashAlign52Bits(hash); - robj *score = createObject(OBJ_STRING, sdsfromlonglong(bits)); + robj *score = createStringObjectFromLongLongWithSds(bits); robj *val = c->argv[longidx + i * 3 + 2]; argv[longidx+i*2] = score; argv[longidx+1+i*2] = val; diff --git a/src/module.c b/src/module.c index 5ae9ca629..57e84e712 100644 --- a/src/module.c +++ b/src/module.c @@ -6037,7 +6037,7 @@ robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int argv[argc++] = createStringObject(buf,len); } else if (*p == 'l') { long long ll = va_arg(ap,long long); - argv[argc++] = createObject(OBJ_STRING,sdsfromlonglong(ll)); + argv[argc++] = createStringObjectFromLongLongWithSds(ll); } else if (*p == 'v') { /* A vector of strings */ robj **v = va_arg(ap, void*); @@ -11049,12 +11049,12 @@ int RM_ScanKey(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleSc vstr = lpGetValue(p,&vlen,&vll); robj *field = (vstr != NULL) ? createStringObject((char*)vstr,vlen) : - createObject(OBJ_STRING,sdsfromlonglong(vll)); + createStringObjectFromLongLongWithSds(vll); p = lpNext(o->ptr,p); vstr = lpGetValue(p,&vlen,&vll); robj *value = (vstr != NULL) ? createStringObject((char*)vstr,vlen) : - createObject(OBJ_STRING,sdsfromlonglong(vll)); + createStringObjectFromLongLongWithSds(vll); fn(key, field, value, privdata); p = lpNext(o->ptr,p); decrRefCount(field); diff --git a/src/object.c b/src/object.c index 6e5e94769..4b3526a02 100644 --- a/src/object.c +++ b/src/object.c @@ -142,33 +142,24 @@ robj *tryCreateStringObject(const char *ptr, size_t len) { return tryCreateRawStringObject(ptr,len); } -/* Create a string object from a long long value. When possible returns a - * shared integer object, or at least an integer encoded one. - * - * If valueobj is non zero, the function avoids returning a shared - * integer, because the object is going to be used as value in the Redis key - * space (for instance when the INCR command is used), so we want LFU/LRU - * values specific for each key. */ -robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj) { +/* Create a string object from a long long value according to the specified flag. */ +#define LL2STROBJ_AUTO 0 /* automatically create the optimal string object */ +#define LL2STROBJ_NO_SHARED 1 /* disallow shared objects */ +#define LL2STROBJ_NO_INT_ENC 2 /* disallow integer encoded objects. */ +robj *createStringObjectFromLongLongWithOptions(long long value, int flag) { robj *o; - if (server.maxmemory == 0 || - !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) - { - /* If the maxmemory policy permits, we can still return shared integers - * even if valueobj is true. */ - valueobj = 0; - } - - if (value >= 0 && value < OBJ_SHARED_INTEGERS && valueobj == 0) { + if (value >= 0 && value < OBJ_SHARED_INTEGERS && flag == LL2STROBJ_AUTO) { o = shared.integers[value]; } else { - if (value >= LONG_MIN && value <= LONG_MAX) { + if ((value >= LONG_MIN && value <= LONG_MAX) && flag != LL2STROBJ_NO_INT_ENC) { o = createObject(OBJ_STRING, NULL); o->encoding = OBJ_ENCODING_INT; o->ptr = (void*)((long)value); } else { - o = createObject(OBJ_STRING,sdsfromlonglong(value)); + char buf[LONG_STR_SIZE]; + int len = ll2string(buf, sizeof(buf), value); + o = createStringObject(buf, len); } } return o; @@ -177,15 +168,27 @@ robj *createStringObjectFromLongLongWithOptions(long long value, int valueobj) { /* Wrapper for createStringObjectFromLongLongWithOptions() always demanding * to create a shared object if possible. */ robj *createStringObjectFromLongLong(long long value) { - return createStringObjectFromLongLongWithOptions(value,0); + return createStringObjectFromLongLongWithOptions(value, LL2STROBJ_AUTO); } -/* Wrapper for createStringObjectFromLongLongWithOptions() avoiding a shared - * object when LFU/LRU info are needed, that is, when the object is used - * as a value in the key space, and Redis is configured to evict based on - * LFU/LRU. */ +/* The function avoids returning a shared integer when LFU/LRU info + * are needed, that is, when the object is used as a value in the key + * space(for instance when the INCR command is used), and Redis is + * configured to evict based on LFU/LRU, so we want LFU/LRU values + * specific for each key. */ robj *createStringObjectFromLongLongForValue(long long value) { - return createStringObjectFromLongLongWithOptions(value,1); + if (server.maxmemory == 0 || !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) { + /* If the maxmemory policy permits, we can still return shared integers */ + return createStringObjectFromLongLongWithOptions(value, LL2STROBJ_AUTO); + } else { + return createStringObjectFromLongLongWithOptions(value, LL2STROBJ_NO_SHARED); + } +} + +/* Create a string object that contains an sds inside it. That means it can't be + * integer encoded (OBJ_ENCODING_INT), and it'll always be an EMBSTR type. */ +robj *createStringObjectFromLongLongWithSds(long long value) { + return createStringObjectFromLongLongWithOptions(value, LL2STROBJ_NO_INT_ENC); } /* Create a string object from a long double. If humanfriendly is non-zero diff --git a/src/rdb.c b/src/rdb.c index 71a49e99b..cfc92e815 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -326,7 +326,7 @@ void *rdbLoadIntegerObject(rio *rdb, int enctype, int flags, size_t *lenptr) { } else if (encode) { return createStringObjectFromLongLongForValue(val); } else { - return createObject(OBJ_STRING,sdsfromlonglong(val)); + return createStringObjectFromLongLongWithSds(val); } } diff --git a/src/sds.c b/src/sds.c index 563f1f0fe..e383e3caa 100644 --- a/src/sds.c +++ b/src/sds.c @@ -38,6 +38,7 @@ #include #include "sds.h" #include "sdsalloc.h" +#include "util.h" const char *SDS_NOINIT = "SDS_NOINIT"; @@ -526,90 +527,13 @@ sds sdscpy(sds s, const char *t) { return sdscpylen(s, t, strlen(t)); } -/* Helper for sdscatlonglong() doing the actual number -> string - * conversion. 's' must point to a string with room for at least - * SDS_LLSTR_SIZE bytes. - * - * The function returns the length of the null-terminated string - * representation stored at 's'. */ -#define SDS_LLSTR_SIZE 21 -int sdsll2str(char *s, long long value) { - char *p, aux; - unsigned long long v; - size_t l; - - /* Generate the string representation, this method produces - * a reversed string. */ - if (value < 0) { - /* Since v is unsigned, if value==LLONG_MIN, -LLONG_MIN will overflow. */ - if (value != LLONG_MIN) { - v = -value; - } else { - v = ((unsigned long long)LLONG_MAX) + 1; - } - } else { - v = value; - } - - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - if (value < 0) *p++ = '-'; - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - -/* Identical sdsll2str(), but for unsigned long long type. */ -int sdsull2str(char *s, unsigned long long v) { - char *p, aux; - size_t l; - - /* Generate the string representation, this method produces - * a reversed string. */ - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - /* Create an sds string from a long long value. It is much faster than: * * sdscatprintf(sdsempty(),"%lld\n", value); */ sds sdsfromlonglong(long long value) { - char buf[SDS_LLSTR_SIZE]; - int len = sdsll2str(buf,value); + char buf[LONG_STR_SIZE]; + int len = ll2string(buf,sizeof(buf),value); return sdsnewlen(buf,len); } @@ -745,8 +669,8 @@ sds sdscatfmt(sds s, char const *fmt, ...) { else num = va_arg(ap,long long); { - char buf[SDS_LLSTR_SIZE]; - l = sdsll2str(buf,num); + char buf[LONG_STR_SIZE]; + l = ll2string(buf,sizeof(buf),num); if (sdsavail(s) < l) { s = sdsMakeRoomFor(s,l); } @@ -762,8 +686,8 @@ sds sdscatfmt(sds s, char const *fmt, ...) { else unum = va_arg(ap,unsigned long long); { - char buf[SDS_LLSTR_SIZE]; - l = sdsull2str(buf,unum); + char buf[LONG_STR_SIZE]; + l = ull2string(buf,sizeof(buf),unum); if (sdsavail(s) < l) { s = sdsMakeRoomFor(s,l); } diff --git a/src/server.h b/src/server.h index 86ae85e58..f262d7766 100644 --- a/src/server.h +++ b/src/server.h @@ -2744,6 +2744,7 @@ robj *getDecodedObject(robj *o); size_t stringObjectLen(robj *o); robj *createStringObjectFromLongLong(long long value); robj *createStringObjectFromLongLongForValue(long long value); +robj *createStringObjectFromLongLongWithSds(long long value); robj *createStringObjectFromLongDouble(long double value, int humanfriendly); robj *createQuicklistObject(void); robj *createListListpackObject(void);