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

 

posted on 2020-12-30 11:39  子虚乌有  阅读(121)  评论(0)    收藏  举报