设为首页 收藏本站
查看: 1197|回复: 0

[经验分享] Redis源码分析(二十八)--- object创建和释放redisObject对象

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-11-5 09:23:56 | 显示全部楼层 |阅读模式
  今天的学习效率比较高,把Rio分析完了,又顺便学习了其中的RedisObject的文件,只要讲的就是RedisObject的一些转换和创建。里面的大多数方法都是非常类似的。列出里面长长的API列表:



    /* ------------  API --------------------- */  
    robj *createObject(int type, void *ptr) /* 最初的创建robj对象方法,后面的创建方法与此类似 */   
    robj *createStringObject(char *ptr, size_t len)  
    robj *createStringObjectFromLongLong(long long value)  
    robj *createStringObjectFromLongDouble(long double value)  
    robj *dupStringObject(robj *o)  
    robj *createListObject(void)  
    robj *createZiplistObject(void)  
    robj *createSetObject(void)  
    robj *createIntsetObject(void)  
    robj *createHashObject(void)  
    robj *createZsetObject(void)  
    robj *createZsetZiplistObject(void)  
    void freeStringObject(robj *o) /* free Obj中的特定对象,这里free的是r->ptr */  
    void freeListObject(robj *o)  
    void freeSetObject(robj *o)  
    void freeZsetObject(robj *o)  
    void freeHashObject(robj *o) /* 释放hashObject有2种形式,1个是o-ptr的字典对象,还有1个回事压缩表o->ptr */  
    void incrRefCount(robj *o) /* robj对象增减引用计数,递增robj中的refcount的值 */  
    void decrRefCount(robj *o) /* 递减robj中的引用计数,引用到0后,释放对象 */  
    void decrRefCountVoid(void *o)  
    robj *resetRefCount(robj *obj)  
    int checkType(redisClient *c, robj *o, int type) /* 检查robj的类型是否为给定的Type类型 */  
    int isObjectRepresentableAsLongLong(robj *o, long long *llval)  
    robj *tryObjectEncoding(robj *o) /* 编码一个robj中的额字符对象,主要是为了省空间 */  
    robj *getDecodedObject(robj *o) /* 获取解码后的robj */  
    int compareStringObjectsWithFlags(robj *a, robj *b, int flags)  
    int compareStringObjects(robj *a, robj *b)  
    int collateStringObjects(robj *a, robj *b)  
    int equalStringObjects(robj *a, robj *b)  
    size_t stringObjectLen(robj *o)  
    int getDoubleFromObject(robj *o, double *target) /* 从robj中获取double数值 */  
    int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg)  
    int getLongDoubleFromObject(robj *o, long double *target)  
    int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg)  
    int getLongLongFromObject(robj *o, long long *target)  
    int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg)  
    int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg)  
    char *strEncoding(int encoding)  
    unsigned long estimateObjectIdleTime(robj *o)  
    robj *objectCommandLookup(redisClient *c, robj *key) /* obj的查找命令, */  
    robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply)  
    void objectCommand(redisClient *c)  

从前往后看,第一个创建obj:



    /* 最初的创建robj对象方法 */   
    robj *createObject(int type, void *ptr) {  
        robj *o = zmalloc(sizeof(*o));  
        o->type = type;  
        o->encoding = REDIS_ENCODING_RAW;  
        o->ptr = ptr;  
        o->refcount = 1;  
      
        /* Set the LRU to the current lruclock (minutes resolution). */  
        o->lru = server.lruclock;  
        return o;  
    }  

有创建就必然会有释放的free方法:



    /* free Obj中的特定对象 */  
    void freeStringObject(robj *o) {  
        if (o->encoding == REDIS_ENCODING_RAW) {  
            sdsfree(o->ptr);  
        }  
    }  

free方法有很多衍生的方法,看你要释放哪种类型的空间了,可以,set,dict,ziplist等等。有下面的一些类型:



    switch(o->type) {  
           case REDIS_STRING: freeStringObject(o); break;  
           case REDIS_LIST: freeListObject(o); break;  
           case REDIS_SET: freeSetObject(o); break;  
           case REDIS_ZSET: freeZsetObject(o); break;  
           case REDIS_HASH: freeHashObject(o); break;  
           default: redisPanic("Unknown object type"); break;  
           }  

重点介绍里面的关于引用计数的相关方法,通过robj->refcount的数值进行控制的:



    /* robj对象增减引用计数,递增robj中的refcount的值 */  
    void incrRefCount(robj *o) {  
        //递增robj中的refcount的值  
        o->refcount++;  
    }  

增加引用计数就一行代码,但是递减的话,我们猜也可以猜到,引用计数变为0的时候,说明无人使用了,就可以释放空间了;



    /* 递减robj中的引用计数,引用到0后,释放对象 */  
    void decrRefCount(robj *o) {  
        //如果之前的引用计数已经<=0了,说明出现异常情况了  
        if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");  
        if (o->refcount == 1) {  
            //如果之前的引用计数为1,再递减一次,恰好内有被任何对象引用了,所以就可以释放对象了  
            switch(o->type) {  
            case REDIS_STRING: freeStringObject(o); break;  
            case REDIS_LIST: freeListObject(o); break;  
            case REDIS_SET: freeSetObject(o); break;  
            case REDIS_ZSET: freeZsetObject(o); break;  
            case REDIS_HASH: freeHashObject(o); break;  
            default: redisPanic("Unknown object type"); break;  
            }  
            zfree(o);  
        } else {  
            //其他对于>1的引用计数的情况,只需要按常规的递减引用计数即可  
            o->refcount--;  
        }  
    }  

标准的引用计数法控制内存的管理,(提醒一下,在JVM中的对象的生命周期管理用的是根搜索法,不是引用计数),还有一个在robj中的编码方法的实现也是定义在这个文件中:



    /* Try to encode a string object in order to save space */  
    /* 编码一个robj中的额字符对象,主要是为了省空间 */  
    robj *tryObjectEncoding(robj *o) {  
        long value;  
        sds s = o->ptr;  
        size_t len;  
      
        if (o->encoding != REDIS_ENCODING_RAW)  
            //如果robj已经被编码了,则直接返回  
            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) */  
         /* 如果robj的引用计数超过1个人引用的时候,是不安全的去编码obj,因为对象是共享的 */  
         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)  
            {  
                //调用sdsRemoveFreeSpace把0->ptr中的字符串中的空格给移除掉  
                o->ptr = sdsRemoveFreeSpace(o->ptr);  
            }  
            /* Return the original object. */  
            return o;  
        }  
            .....  

就是移除字符串中的空格所占的空间。想对应也存在一个getDecodeObject(),:



    /* 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. */  
    /* 获取解码后的robj */  
    robj *getDecodedObject(robj *o) {  
        robj *dec;  
      
        if (o->encoding == REDIS_ENCODING_RAW) {  
            //如果没有编码方式,则直接增加引用计数,并返回  
            incrRefCount(o);  
            return o;  
        }  
        if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {  
            char buf[32];  
            //如果是string,Type而且是encoding_int方式的,先做一步转换  
            ll2string(buf,32,(long)o->ptr);  
            dec = createStringObject(buf,strlen(buf));  
            return dec;  
        } else {  
            redisPanic("Unknown encoding type");  
        }  
    }  

以上就是对于对于RedisObject的简单分析。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-27107-1-1.html 上篇帖子: Redis源码分析(二十七)--- rio系统I/O的封装 下篇帖子: Redis源码分析(二十九)--- bio后台I/O服务的实现
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表