/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; if (o->encoding != REDIS_ENCODING_RAW) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ len = sdslen(s); if (len > 21 || !string2l(s,len,&value)) { /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that for larger strings, using the arbitrary value * of 32 bytes. This code was backported from the unstable branch * where this is performed when the object is too large to be * encoded as EMBSTR. */ if (len > 32 && o->encoding == REDIS_ENCODING_RAW && sdsavail(s) > len/10) { o->ptr = sdsRemoveFreeSpace(o->ptr); } /* Return the original object. */ return o; } /* Ok, this object can be encoded... * * 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 * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return o; } }
value_t *createValueFromStr(void *s, size_t len) { long v; value_t *val; // first we try to encode the string as a long. if (len > 21 || !string2l(s, len, &v)) { val = createValue(ENCODING_RAW, sdsnewlen(s, len)); } else { val = createValue(ENCODING_INT, NULL); val->ptr = (void*) ((long) v); } return val; }
// try encode a string value as integer. value_t *tryValueEncoding(value_t *val) { if (val->encoding == ENCODING_INT) return val; size_t len = sdslen(val->ptr); long v; if (len > 21 || !string2l(val->ptr, len, &v)) { if (len > 32 && sdsavail(val->ptr) > len / 10) { val->ptr = sdsRemoveFreeSpace(val->ptr); } return val; } else { val->encoding = ENCODING_INT; sdsfree(val->ptr); val->ptr = (void*) ((long) v); } }
/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; if (o->encoding != REDIS_ENCODING_RAW) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssert(o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ if (!string2l(s,sdslen(s),&value)) return 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. * * 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 * algorithm to work well. */ if (!server.ds_enabled && server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS && pthread_equal(pthread_self(),server.mainthread)) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return o; } }
/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { //看看是否可以对对象做压缩。目前只支持很短的数字字符串,将其转为数字存储。 long value; sds s = o->ptr; if (o->encoding != REDIS_ENCODING_RAW) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* Check if we can represent this string as a long integer */ if (!string2l(s,sdslen(s),&value)) return o; /* Ok, this object can be encoded... * * 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 * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { o->encoding = REDIS_ENCODING_INT; sdsfree(o->ptr); o->ptr = (void*) value; return o; } }
void test_string2l(void) { char buf[32]; long v; /* May not start with +. */ strcpy(buf,"+1"); assert(string2l(buf,strlen(buf),&v) == 0); /* May not start with 0. */ strcpy(buf,"01"); assert(string2l(buf,strlen(buf),&v) == 0); strcpy(buf,"-1"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == -1); strcpy(buf,"0"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == 0); strcpy(buf,"1"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == 1); strcpy(buf,"99"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == 99); strcpy(buf,"-99"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == -99); #if LONG_MAX != LLONG_MAX strcpy(buf,"-2147483648"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == LONG_MIN); strcpy(buf,"-2147483649"); /* overflow */ assert(string2l(buf,strlen(buf),&v) == 0); strcpy(buf,"2147483647"); assert(string2l(buf,strlen(buf),&v) == 1); assert(v == LONG_MAX); strcpy(buf,"2147483648"); /* overflow */ assert(string2l(buf,strlen(buf),&v) == 0); #endif }
// 尝试对字符串对象进行编码,以节约内存。 robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; /* Make sure this is a string object, the only type we encode * in this function. Other types use encoded memory efficient * representations but are handled by the commands implementing * the type. */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* We try some specialized encoding only for objects that are * RAW or EMBSTR encoded, in other words objects that are still * in represented by an actually array of chars. */ // 只在字符串的编码为 RAW 或者 EMBSTR 时尝试进行编码 if (!sdsEncodedObject(o)) return o; /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis and may end in places where * they are not handled. We handle them only as values in the keyspace. */ // 不对共享对象进行编码 if (o->refcount > 1) return o; /* Check if we can represent this string as a long integer. * Note that we are sure that a string larger than 21 chars is not * representable as a 32 nor 64 bit integer. */ // 对字符串进行检查 // 只对长度小于或等于 21 字节,并且可以被解释为整数的字符串进行编码 len = sdslen(s); if (len <= 21 && string2l(s,len,&value)) { //如果是整数字符串 /* This object is encodable as a long. Try to use a shared object. * Note that we avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); //如果是10000以内的字符串,则直接使用shared.integers[value]标记就行了,增加其引用计数 incrRefCount(shared.integers[value]); return shared.integers[value]; } else { //如果是大于10000的字符串,则直接转换为REDIS_ENCODING_INT编码方式存储, if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr); o->encoding = REDIS_ENCODING_INT; o->ptr = (void*) value; //直接用ptr存储字符串对应的整数,转换为地址 return o; } } /* If the string is small and is still RAW encoded, * try the EMBSTR encoding which is more efficient. * In this representation the object and the SDS string are allocated * in the same chunk of memory to save space and cache misses. */ // 尝试将 RAW 编码的字符串编码为 EMBSTR 编码 if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) { //如果字符串小于39,并且之前不是REDIS_ENCODING_EMBSTR(obj+sdshdr+data)内存连续的,则转换为REDIS_ENCODING_EMBSTR内存连续编码方式 robj *emb; if (o->encoding == REDIS_ENCODING_EMBSTR) return o; emb = createEmbeddedStringObject(s,sdslen(s)); decrRefCount(o); return emb; } /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that only for relatively large strings as this branch * is only entered if the length of the string is greater than * REDIS_ENCODING_EMBSTR_SIZE_LIMIT. */ // 这个对象没办法进行编码,尝试从 SDS 中移除所有空余空间 if (o->encoding == REDIS_ENCODING_RAW && sdsavail(s) > len/10) //剩余空间大于总分配obj空间的十分之一 { o->ptr = sdsRemoveFreeSpace(o->ptr); } /* Return the original object. */ return o; }
/* Try to encode a string object in order to save space */ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; /* Make sure this is a string object, the only type we encode * in this function. Other types use encoded memory efficient * representations but are handled by the commands implementing * the type. */ serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); /* We try some specialized encoding only for objects that are * RAW or EMBSTR encoded, in other words objects that are still * in represented by an actually array of chars. */ if (!sdsEncodedObject(o)) return o; /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis and may end in places where * they are not handled. We handle them only as values in the keyspace. */ if (o->refcount > 1) return o; /* Check if we can represent this string as a long integer. * Note that we are sure that a string larger than 20 chars is not * representable as a 32 nor 64 bit integer. */ len = sdslen(s); if (len <= 20 && string2l(s,len,&value)) { /* This object is encodable as a long. Try to use a shared object. * Note that we avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ if ((server.maxmemory == 0 || (server.maxmemory_policy != MAXMEMORY_VOLATILE_LRU && server.maxmemory_policy != MAXMEMORY_ALLKEYS_LRU)) && value >= 0 && value < OBJ_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { if (o->encoding == OBJ_ENCODING_RAW) sdsfree(o->ptr); o->encoding = OBJ_ENCODING_INT; o->ptr = (void*) value; return o; } } /* If the string is small and is still RAW encoded, * try the EMBSTR encoding which is more efficient. * In this representation the object and the SDS string are allocated * in the same chunk of memory to save space and cache misses. */ if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) { robj *emb; if (o->encoding == OBJ_ENCODING_EMBSTR) return o; emb = createEmbeddedStringObject(s,sdslen(s)); decrRefCount(o); return emb; } /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that only for relatively large strings as this branch * is only entered if the length of the string is greater than * OBJ_ENCODING_EMBSTR_SIZE_LIMIT. */ if (o->encoding == OBJ_ENCODING_RAW && sdsavail(s) > len/10) { o->ptr = sdsRemoveFreeSpace(o->ptr); } /* Return the original object. */ return o; }
/* Try to encode a string object in order to save space * 尝试编译字符串对象 目的未来节省空间*/ robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; if (o->encoding == REDIS_ENCODING_INT) return o; /* Already encoded */ /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis. Encoded objects can only * appear as "values" (and not, for instance, as keys) */ if (o->refcount > 1) return o; /* Currently we try to encode only strings */ redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); /* Check if we can represent this string as a long integer. * Note that we are sure that a string larger than 21 chars is not * representable as a 64 bit integer. */ len = sdslen(s); if (len > 21 || !string2l(s,len,&value)) { /* Integer encoding not possible. Check if we can use EMBSTR. */ if (sdslen(s) <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) { robj *emb = createEmbeddedStringObject(s,sdslen(s)); decrRefCount(o); return emb; } else { /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that only for relatively large strings as this branch * is only entered if the length of the string is greater than * REDIS_ENCODING_EMBSTR_SIZE_LIMIT. */ if (o->encoding == REDIS_ENCODING_RAW && sdsavail(s) > len/10) { o->ptr = sdsRemoveFreeSpace(o->ptr); } /* Return the original object. */ return o; } } /* Ok, this object can be encoded... * * 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 * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr); o->encoding = REDIS_ENCODING_INT; o->ptr = (void*) value; return o; } }
robj *tryObjectEncoding(robj *o) { long value; sds s = o->ptr; size_t len; /* Make sure this is a string object, the only type we encode * in this function. Other types use encoded memory efficient * representations but are handled by the commands implementing * the type. */ serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); /* We try some specialized encoding only for objects that are * RAW or EMBSTR encoded, in other words objects that are still * in represented by an actually array of chars. */ //如果字符串对象的编码类型为RAW或EMBSTR时,才对其重新编码 if (!sdsEncodedObject(o)) return o; /* It's not safe to encode shared objects: shared objects can be shared * everywhere in the "object space" of Redis and may end in places where * they are not handled. We handle them only as values in the keyspace. */ //如果refcount大于1,则说明对象的ptr指向的值是共享的,不对共享对象进行编码 if (o->refcount > 1) return o; /* Check if we can represent this string as a long integer. * Note that we are sure that a string larger than 20 chars is not * representable as a 32 nor 64 bit integer. */ len = sdslen(s); //获得字符串s的长度 //如果len小于等于20,表示符合long long可以表示的范围,且可以转换为long类型的字符串进行编码 if (len <= 20 && string2l(s,len,&value)) { /* This object is encodable as a long. Try to use a shared object. * Note that we avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ if ((server.maxmemory == 0 || (server.maxmemory_policy != MAXMEMORY_VOLATILE_LRU && server.maxmemory_policy != MAXMEMORY_ALLKEYS_LRU)) && value >= 0 && value < OBJ_SHARED_INTEGERS) //如果value处于共享整数的范围内 { decrRefCount(o); //原对象的引用计数减1,释放对象 incrRefCount(shared.integers[value]); //增加共享对象的引用计数 return shared.integers[value]; //返回一个编码为整数的字符串对象 } else { //如果不处于共享整数的范围 if (o->encoding == OBJ_ENCODING_RAW) sdsfree(o->ptr); //释放编码为OBJ_ENCODING_RAW的对象 o->encoding = OBJ_ENCODING_INT; //转换为OBJ_ENCODING_INT编码 o->ptr = (void*) value; //指针ptr指向value对象 return o; } } /* If the string is small and is still RAW encoded, * try the EMBSTR encoding which is more efficient. * In this representation the object and the SDS string are allocated * in the same chunk of memory to save space and cache misses. */ //如果len小于44,44是最大的编码为EMBSTR类型的字符串对象长度 if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) { robj *emb; if (o->encoding == OBJ_ENCODING_EMBSTR) return o; //将RAW对象转换为OBJ_ENCODING_EMBSTR编码类型 emb = createEmbeddedStringObject(s,sdslen(s)); //创建一个编码类型为OBJ_ENCODING_EMBSTR的字符串对象 decrRefCount(o); //释放之前的对象 return emb; } /* We can't encode the object... * * Do the last try, and at least optimize the SDS string inside * the string object to require little space, in case there * is more than 10% of free space at the end of the SDS string. * * We do that only for relatively large strings as this branch * is only entered if the length of the string is greater than * OBJ_ENCODING_EMBSTR_SIZE_LIMIT. */ //无法进行编码,但是如果s的未使用的空间大于使用空间的10分之1 if (o->encoding == OBJ_ENCODING_RAW && sdsavail(s) > len/10) { o->ptr = sdsRemoveFreeSpace(o->ptr); //释放所有的未使用空间 } /* Return the original object. */ return o; }