robj *createStringObject(char *ptr, size_t len) { /* 这两种方式的区别是字节数少的时候,直接一次性分配zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1) 如果大于39则分别分配sizeof(robj)和sizeof(struct sdshdr)+len空间 */ if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else return createRawStringObject(ptr,len); }
/* Duplicate a string object, with the guarantee that the returned object * has the same encoding as the original one. * * This function also guarantees that duplicating a small integere object * (or a string object that contains a representation of a small integer) * will always result in a fresh object that is unshared (refcount == 1). * * The resulting object always has refcount set to 1. */ robj *dupStringObject(robj *o) { robj *d; serverAssert(o->type == OBJ_STRING); switch(o->encoding) { case OBJ_ENCODING_RAW: return createRawStringObject(o->ptr,sdslen(o->ptr)); case OBJ_ENCODING_EMBSTR: return createEmbeddedStringObject(o->ptr,sdslen(o->ptr)); case OBJ_ENCODING_INT: d = createObject(OBJ_STRING, NULL); d->encoding = OBJ_ENCODING_INT; d->ptr = o->ptr; return d; default: serverPanic("Wrong encoding."); break; } }
//返回 复制的o对象的副本的地址,且创建的对象非共享 robj *dupStringObject(robj *o) { robj *d; serverAssert(o->type == OBJ_STRING); //一定是OBJ_STRING类型 switch(o->encoding) { //根据不同的编码类型 case OBJ_ENCODING_RAW: return createRawStringObject(o->ptr,sdslen(o->ptr)); //创建的对象非共享 case OBJ_ENCODING_EMBSTR: return createEmbeddedStringObject(o->ptr,sdslen(o->ptr)); //创建的对象非共享 case OBJ_ENCODING_INT: //整数编码类型 d = createObject(OBJ_STRING, NULL); //即使是共享整数范围内的整数,创建的对象也是非共享的 d->encoding = OBJ_ENCODING_INT; d->ptr = o->ptr; return d; default: serverPanic("Wrong encoding."); break; } }
/* Duplicate a string object, with the guarantee that the returned object * has the same encoding as the original one. * * This function also guarantees that duplicating a small integere object * (or a string object that contains a representation of a small integer) * will always result in a fresh object that is unshared (refcount == 1). * * The resulting object always has refcount set to 1. */ robj *dupStringObject(robj *o) { robj *d; assert(o->type == OBJ_STRING); switch(o->encoding) { case OBJ_ENCODING_RAW: return createRawStringObject(o->ptr,sdslen(o->ptr)); case OBJ_ENCODING_EMBSTR: return createEmbeddedStringObject(o->ptr,sdslen(o->ptr)); case OBJ_ENCODING_INT: d = createObject(OBJ_STRING, NULL); d->encoding = OBJ_ENCODING_INT; d->ptr = o->ptr; return d; default: rr_log(RR_LOG_ERROR, "Wrong encoding"); return NULL; break; } }
// 尝试对字符串对象进行编码,以节约内存。 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; }
robj *createStringObject(const char *ptr, size_t len) { if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) return createEmbeddedStringObject(ptr,len); else return createRawStringObject(ptr,len); }
/* 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; }