redis6.0.5之redisObject阅读笔记--redis对象(redisObject)第二部分
************************************************************************************** #define sdsEncodedObject(objptr) (objptr->encoding == OBJ_ENCODING_RAW || objptr->encoding == OBJ_ENCODING_EMBSTR) 定义字符串编码的两种类型 /* 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. */ 对共享对象编码是不安全的,因为共享对象能够在redis的任何对象空间中分享, 而且可能在没有处理的地方结束。我们只处理那些在键空间中的值。 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. */ 检查字符串对象是否代表一个整型。注意到如果一个字符串长度大于20个字符,那么就不代表一个32位或者64位的整型。 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. */ 如果符合上述条件,那么这个是一个长整型的编码对象。尝试去使用一个共对象。 如果最大内存启用,那么我们应该避免去使用共享整型对象,因为每个对象需要一个独立的LRU域, 用于LRU的淘汰算法。 if ((server.maxmemory == 0 || !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) && value >= 0 && value < OBJ_SHARED_INTEGERS) { //以上情况可以共享 decrRefCount(o);////将原对象引用减少1 incrRefCount(shared.integers[value]); //将共享对象的引用加1 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; } else if (o->encoding == OBJ_ENCODING_EMBSTR) { //因为嵌入式编码是连在一起的,所以需要全部重建,而不是只赋值 decrRefCount(o);//将原对象引用减少1 return createStringObjectFromLongLongForValue(value);//重建 } } } /* 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. */ 如果字符串很短并且是原始编码的,是可以考虑使用更加高效的嵌入式字符串编码。 用嵌入式字符串编码SDS对象,可以使得内存分配在同一个块内,母的是为了节约空间和缓存不命中。 (即连续的内存空间更加容易命中缓存) if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) { robj *emb; if (o->encoding == OBJ_ENCODING_EMBSTR) return o; //已经是嵌入式,无需改变 emb = createEmbeddedStringObject(s,sdslen(s)); //否则创建嵌入式编码字符串对象 decrRefCount(o); //将原对象引用减少1 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. 做最后的努力,优化字符串对象中的SDS字符串,让其使用最少的内存空间, 如果SDS字符串末尾的空闲空间恰好大于百分之10(我们就可以优化) * 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. */ 对这种优化我们只针对比较大的字符串对象,因为这个分支的准入条件是 字符串长度大于OBJ_ENCODING_EMBSTR_SIZE_LIMIT(44) trimStringObjectIfNeeded(o); /* Return the original object. */ return o; } /* 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. This happens because SDS strings tend to overallocate to avoid * wasting too much time in allocations when appending to the string. */ void trimStringObjectIfNeeded(robj *o) { if (o->encoding == OBJ_ENCODING_RAW && sdsavail(o->ptr) > sdslen(o->ptr)/10) { o->ptr = sdsRemoveFreeSpace(o->ptr); } } ************************************************************************************** /* Get a decoded version of an encoded object (returned as a new object). * If the object is already raw-encoded just increment the ref count. */ 获取一个编码对象的解码版本(返回一个新对象)。如果对象本身就是原始编码类型,那么引用计数加1. robj *getDecodedObject(robj *o) { robj *dec; //如果本身就是原始字符串编码,直接返回对象,引用计数加1 if (sdsEncodedObject(o)) { incrRefCount(o); return o; } //如果是字符串编码并且是整型编码,那么创建一个新对象返回。 if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) { char buf[32]; ll2string(buf,32,(long)o->ptr); dec = createStringObject(buf,strlen(buf)); return dec; } else { serverPanic("Unknown encoding type"); } } ************************************************************************************** /* Compare two string objects via strcmp() or strcoll() depending on flags. * Note that the objects may be integer-encoded. In such a case we * use ll2string() to get a string representation of the numbers on the stack * and compare the strings, it's much faster than calling getDecodedObject(). 比较两个字符串对象,根据标志使用函数strcmp还是函数strcoll。注意到对象可能是整型编码。 在这种情况下,我们使用函数ll2string去获取一个栈上数字的字符串表达式来比较字符串, 这种方式比调用函数getDecodeObject更快。 * Important note: when REDIS_COMPARE_BINARY is used a binary-safe comparison * is used. */ 重要提示:当使用REDIS_COMPARE_BINARY时,我们采用的是二进制安全的比较 #define REDIS_COMPARE_BINARY (1<<0) #define REDIS_COMPARE_COLL (1<<1) int compareStringObjectsWithFlags(robj *a, robj *b, int flags) { //确认都是字符串对象类型 serverAssertWithInfo(NULL,a,a->type == OBJ_STRING && b->type == OBJ_STRING); char bufa[128], bufb[128], *astr, *bstr; size_t alen, blen, minlen; if (a == b) return 0; //ab相等 if (sdsEncodedObject(a)) { //是char数据类型的 astr = a->ptr; alen = sdslen(astr); } else { //整型的 alen = ll2string(bufa,sizeof(bufa),(long) a->ptr); astr = bufa; } if (sdsEncodedObject(b)) { bstr = b->ptr; blen = sdslen(bstr); } else { blen = ll2string(bufb,sizeof(bufb),(long) b->ptr); bstr = bufb; } if (flags & REDIS_COMPARE_COLL) { return strcoll(astr,bstr); } else { int cmp; minlen = (alen < blen) ? alen : blen; cmp = memcmp(astr,bstr,minlen);//对共同部分进行挨个字符比较 if (cmp == 0) return alen-blen; return cmp; } } /* Wrapper for compareStringObjectsWithFlags() using binary comparison. */ 使用二进制安全比较函数 int compareStringObjects(robj *a, robj *b) { return compareStringObjectsWithFlags(a,b,REDIS_COMPARE_BINARY); } 使用collation函数比较 /* Wrapper for compareStringObjectsWithFlags() using collation. */ int collateStringObjects(robj *a, robj *b) { return compareStringObjectsWithFlags(a,b,REDIS_COMPARE_COLL); } ************************************************************************************** /* Equal string objects return 1 if the two objects are the same from the * point of view of a string comparison, otherwise 0 is returned. Note that * this function is faster then checking for (compareStringObject(a,b) == 0) * because it can perform some more optimization. */ 如果从字符串比较角度出发,两个字符串对象是相同的,那么返回1,否则返回0。 注意到这个函数比compareStringObject(a,b) == 0速度更快,因为它做了一些优化。 int equalStringObjects(robj *a, robj *b) { if (a->encoding == OBJ_ENCODING_INT && b->encoding == OBJ_ENCODING_INT){ /* If both strings are integer encoded just check if the stored * long is the same. */ //如果两个字符串都是整型编码,就直接检查存储的长整形是否相等 return a->ptr == b->ptr; } else { return compareStringObjects(a,b) == 0; //其它情况调用函数compareStringObjects判断 } } ************************************************************************************** 获取字符串对象长度 size_t stringObjectLen(robj *o) { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { return sdslen(o->ptr); //字符类型,直接获取字符串长度即可 } else { return sdigits10((long)o->ptr); //数字情况,则调用函数sdigits10计算 } } /* Like digits10() but for signed values. */ uint32_t sdigits10(int64_t v) { if (v < 0) { /* Abs value of LLONG_MIN requires special handling. */ 32位最大值需要特殊处理 uint64_t uv = (v != LLONG_MIN) ? (uint64_t)-v : ((uint64_t) LLONG_MAX)+1; return digits10(uv)+1; /* +1 for the minus. */ } else { return digits10(v); } } 返回10进制下字符串转化为数字的个数 /* Return the number of digits of 'v' when converted to string in radix 10. * See ll2string() for more information. */ uint32_t digits10(uint64_t v) { if (v < 10) return 1; if (v < 100) return 2; if (v < 1000) return 3; if (v < 1000000000000UL) { if (v < 100000000UL) { if (v < 1000000) { if (v < 10000) return 4; return 5 + (v >= 100000); } return 7 + (v >= 10000000UL); } if (v < 10000000000UL) { return 9 + (v >= 1000000000UL); } return 11 + (v >= 100000000000UL); } return 12 + digits10(v / 1000000000000UL); } ************************************************************************************** 获取浮点数和长整型的数值 int getDoubleFromObject(const robj *o, double *target) { double value; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { if (!string2d(o->ptr, sdslen(o->ptr), &value)) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } *target = value; return C_OK; } ************************************************************************************** int getDoubleFromObject(const robj *o, double *target) { double value; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { if (!string2d(o->ptr, sdslen(o->ptr), &value)) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } *target = value; return C_OK; } int getDoubleFromObjectOrReply(client *c, robj *o, double *target, const char *msg) { double value; if (getDoubleFromObject(o, &value) != C_OK) { if (msg != NULL) { addReplyError(c,(char*)msg); } else { addReplyError(c,"value is not a valid float"); } return C_ERR; } *target = value; return C_OK; } int getLongDoubleFromObject(robj *o, long double *target) { long double value; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { if (!string2ld(o->ptr, sdslen(o->ptr), &value)) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } *target = value; return C_OK; } int getLongDoubleFromObjectOrReply(client *c, robj *o, long double *target, const char *msg) { long double value; if (getLongDoubleFromObject(o, &value) != C_OK) { if (msg != NULL) { addReplyError(c,(char*)msg); } else { addReplyError(c,"value is not a valid float"); } return C_ERR; } *target = value; return C_OK; } int getLongLongFromObject(robj *o, long long *target) { long long value; if (o == NULL) { value = 0; } else { serverAssertWithInfo(NULL,o,o->type == OBJ_STRING); if (sdsEncodedObject(o)) { if (string2ll(o->ptr,sdslen(o->ptr),&value) == 0) return C_ERR; } else if (o->encoding == OBJ_ENCODING_INT) { value = (long)o->ptr; } else { serverPanic("Unknown string encoding"); } } if (target) *target = value; return C_OK; } int getLongLongFromObjectOrReply(client *c, robj *o, long long *target, const char *msg) { long long value; if (getLongLongFromObject(o, &value) != C_OK) { if (msg != NULL) { addReplyError(c,(char*)msg); } else { addReplyError(c,"value is not an integer or out of range"); } return C_ERR; } *target = value; return C_OK; } int getLongFromObjectOrReply(client *c, robj *o, long *target, const char *msg) { long long value; if (getLongLongFromObjectOrReply(c, o, &value, msg) != C_OK) return C_ERR; if (value < LONG_MIN || value > LONG_MAX) { if (msg != NULL) { addReplyError(c,(char*)msg); } else { addReplyError(c,"value is out of range"); } return C_ERR; } *target = value; return C_OK; } ************************************************************************************** 返回编码类型 char *strEncoding(int encoding) { switch(encoding) { case OBJ_ENCODING_RAW: return "raw"; case OBJ_ENCODING_INT: return "int"; case OBJ_ENCODING_HT: return "hashtable"; case OBJ_ENCODING_QUICKLIST: return "quicklist"; case OBJ_ENCODING_ZIPLIST: return "ziplist"; case OBJ_ENCODING_INTSET: return "intset"; case OBJ_ENCODING_SKIPLIST: return "skiplist"; case OBJ_ENCODING_EMBSTR: return "embstr"; default: return "unknown"; } } ***************************************************************