**************************************************************************************
#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";
}
}
***************************************************************