请选择 进入手机版 | 继续访问电脑版

Redis中国用户组(CRUG)论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: 活动 交友 discuz
查看: 479|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    2017-6-13 10:19
  • 签到天数: 92 天

    [LV.6]常住居民II

    360

    主题

    465

    帖子

    3718

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    3718

    最佳新人活跃会员宣传达人突出贡献优秀版主荣誉管理论坛元老

    发表于 2016-4-12 09:55:50 | 显示全部楼层 |阅读模式

    今天的学习效率比较高,把Rio分析完了,又顺便学习了其中的RedisObject的文件,只要讲的就是RedisObject的一些转换和创建。里面的大多数方法都是非常类似的。列出里面长长的API列表:

    1. /* ------------  API --------------------- */  
    2. robj *createObject(int type, void *ptr) /* 最初的创建robj对象方法,后面的创建方法与此类似 */   
    3. robj *createStringObject(char *ptr, size_t len)  
    4. robj *createStringObjectFromLongLong(long long value)  
    5. robj *createStringObjectFromLongDouble(long double value)  
    6. robj *dupStringObject(robj *o)  
    7. robj *createListObject(void)  
    8. robj *createZiplistObject(void)  
    9. robj *createSetObject(void)  
    10. robj *createIntsetObject(void)  
    11. robj *createHashObject(void)  
    12. robj *createZsetObject(void)  
    13. robj *createZsetZiplistObject(void)  
    14. void freeStringObject(robj *o) /* free Obj中的特定对象,这里free的是r->ptr */  
    15. void freeListObject(robj *o)  
    16. void freeSetObject(robj *o)  
    17. void freeZsetObject(robj *o)  
    18. void freeHashObject(robj *o) /* 释放hashObject有2种形式,1个是o-ptr的字典对象,还有1个回事压缩表o->ptr */  
    19. void incrRefCount(robj *o) /* robj对象增减引用计数,递增robj中的refcount的值 */  
    20. void decrRefCount(robj *o) /* 递减robj中的引用计数,引用到0后,释放对象 */  
    21. void decrRefCountVoid(void *o)  
    22. robj *resetRefCount(robj *obj)  
    23. int checkType(redisClient *c, robj *o, int type) /* 检查robj的类型是否为给定的Type类型 */  
    24. int isObjectRepresentableAsLongLong(robj *o, long long *llval)  
    25. robj *tryObjectEncoding(robj *o) /* 编码一个robj中的额字符对象,主要是为了省空间 */  
    26. robj *getDecodedObject(robj *o) /* 获取解码后的robj */  
    27. int compareStringObjectsWithFlags(robj *a, robj *b, int flags)  
    28. int compareStringObjects(robj *a, robj *b)  
    29. int collateStringObjects(robj *a, robj *b)  
    30. int equalStringObjects(robj *a, robj *b)  
    31. size_t stringObjectLen(robj *o)  
    32. int getDoubleFromObject(robj *o, double *target) /* 从robj中获取double数值 */  
    33. int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg)  
    34. int getLongDoubleFromObject(robj *o, long double *target)  
    35. int getLongDoubleFromObjectOrReply(redisClient *c, robj *o, long double *target, const char *msg)  
    36. int getLongLongFromObject(robj *o, long long *target)  
    37. int getLongLongFromObjectOrReply(redisClient *c, robj *o, long long *target, const char *msg)  
    38. int getLongFromObjectOrReply(redisClient *c, robj *o, long *target, const char *msg)  
    39. char *strEncoding(int encoding)  
    40. unsigned long estimateObjectIdleTime(robj *o)  
    41. robj *objectCommandLookup(redisClient *c, robj *key) /* obj的查找命令, */  
    42. robj *objectCommandLookupOrReply(redisClient *c, robj *key, robj *reply)  
    43. void objectCommand(redisClient *c)  
    复制代码

    从前往后看,第一个创建obj:
    1. /* 最初的创建robj对象方法 */   
    2. robj *createObject(int type, void *ptr) {  
    3.     robj *o = zmalloc(sizeof(*o));  
    4.     o->type = type;  
    5.     o->encoding = REDIS_ENCODING_RAW;  
    6.     o->ptr = ptr;  
    7.     o->refcount = 1;  
    8.   
    9.     /* Set the LRU to the current lruclock (minutes resolution). */  
    10.     o->lru = server.lruclock;  
    11.     return o;  
    12. }  
    复制代码

    有创建就必然会有释放的free方法:
    1. /* free Obj中的特定对象 */  
    2. void freeStringObject(robj *o) {  
    3.     if (o->encoding == REDIS_ENCODING_RAW) {  
    4.         sdsfree(o->ptr);  
    5.     }  
    6. }  
    复制代码

    free方法有很多衍生的方法,看你要释放哪种类型的空间了,可以,set,dict,ziplist等等。有下面的一些类型:
    1. switch(o->type) {  
    2.        case REDIS_STRING: freeStringObject(o); break;  
    3.        case REDIS_LIST: freeListObject(o); break;  
    4.        case REDIS_SET: freeSetObject(o); break;  
    5.        case REDIS_ZSET: freeZsetObject(o); break;  
    6.        case REDIS_HASH: freeHashObject(o); break;  
    7.        default: redisPanic("Unknown object type"); break;  
    8.        }  
    复制代码

    重点介绍里面的关于引用计数的相关方法,通过robj->refcount的数值进行控制的:
    1. /* robj对象增减引用计数,递增robj中的refcount的值 */  
    2. void incrRefCount(robj *o) {  
    3.     //递增robj中的refcount的值  
    4.     o->refcount++;  
    5. }  
    复制代码

    增加引用计数就一行代码,但是递减的话,我们猜也可以猜到,引用计数变为0的时候,说明无人使用了,就可以释放空间了;
    1. /* 递减robj中的引用计数,引用到0后,释放对象 */  
    2. void decrRefCount(robj *o) {  
    3.     //如果之前的引用计数已经<=0了,说明出现异常情况了  
    4.     if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");  
    5.     if (o->refcount == 1) {  
    6.         //如果之前的引用计数为1,再递减一次,恰好内有被任何对象引用了,所以就可以释放对象了  
    7.         switch(o->type) {  
    8.         case REDIS_STRING: freeStringObject(o); break;  
    9.         case REDIS_LIST: freeListObject(o); break;  
    10.         case REDIS_SET: freeSetObject(o); break;  
    11.         case REDIS_ZSET: freeZsetObject(o); break;  
    12.         case REDIS_HASH: freeHashObject(o); break;  
    13.         default: redisPanic("Unknown object type"); break;  
    14.         }  
    15.         zfree(o);  
    16.     } else {  
    17.         //其他对于>1的引用计数的情况,只需要按常规的递减引用计数即可  
    18.         o->refcount--;  
    19.     }  
    20. }  
    复制代码

    标准的引用计数法控制内存的管理,(提醒一下,在JVM中的对象的生命周期管理用的是根搜索法,不是引用计数),还有一个在robj中的编码方法的实现也是定义在这个文件中:
    1. /* Try to encode a string object in order to save space */  
    2. /* 编码一个robj中的额字符对象,主要是为了省空间 */  
    3. robj *tryObjectEncoding(robj *o) {  
    4.     long value;  
    5.     sds s = o->ptr;  
    6.     size_t len;  
    7.   
    8.     if (o->encoding != REDIS_ENCODING_RAW)  
    9.         //如果robj已经被编码了,则直接返回  
    10.         return o; /* Already encoded */  
    11.   
    12.     /* It's not safe to encode shared objects: shared objects can be shared
    13.      * everywhere in the "object space" of Redis. Encoded objects can only
    14.      * appear as "values" (and not, for instance, as keys) */  
    15.      /* 如果robj的引用计数超过1个人引用的时候,是不安全的去编码obj,因为对象是共享的 */  
    16.      if (o->refcount > 1) return o;  
    17.   
    18.     /* Currently we try to encode only strings */  
    19.     redisAssertWithInfo(NULL,o,o->type == REDIS_STRING);  
    20.   
    21.     /* Check if we can represent this string as a long integer */  
    22.     len = sdslen(s);  
    23.     if (len > 21 || !string2l(s,len,&value)) {  
    24.         /* We can't encode the object...
    25.          *
    26.          * Do the last try, and at least optimize the SDS string inside
    27.          * the string object to require little space, in case there
    28.          * is more than 10% of free space at the end of the SDS string.
    29.          *
    30.          * We do that for larger strings, using the arbitrary value
    31.          * of 32 bytes. This code was backported from the unstable branch
    32.          * where this is performed when the object is too large to be
    33.          * encoded as EMBSTR. */  
    34.         if (len > 32 &&  
    35.             o->encoding == REDIS_ENCODING_RAW &&  
    36.             sdsavail(s) > len/10)  
    37.         {  
    38.             //调用sdsRemoveFreeSpace把0->ptr中的字符串中的空格给移除掉  
    39.             o->ptr = sdsRemoveFreeSpace(o->ptr);  
    40.         }  
    41.         /* Return the original object. */  
    42.         return o;  
    43.     }  
    44.         .....  
    复制代码

    就是移除字符串中的空格所占的空间。想对应也存在一个getDecodeObject(),:
    1. [cpp] view plain copy print?
    2. /* Get a decoded version of an encoded object (returned as a new object).
    3. * If the object is already raw-encoded just increment the ref count. */  
    4. /* 获取解码后的robj */  
    5. robj *getDecodedObject(robj *o) {  
    6.     robj *dec;  
    7.   
    8.     if (o->encoding == REDIS_ENCODING_RAW) {  
    9.         //如果没有编码方式,则直接增加引用计数,并返回  
    10.         incrRefCount(o);  
    11.         return o;  
    12.     }  
    13.     if (o->type == REDIS_STRING && o->encoding == REDIS_ENCODING_INT) {  
    14.         char buf[32];  
    15.         //如果是string,Type而且是encoding_int方式的,先做一步转换  
    16.         ll2string(buf,32,(long)o->ptr);  
    17.         dec = createStringObject(buf,strlen(buf));  
    18.         return dec;  
    19.     } else {  
    20.         redisPanic("Unknown encoding type");  
    21.     }  
    22. }  
    复制代码

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



    转自:http://blog.csdn.net/androidlushangderen/article/details/40716469
    上一篇:Redis源码分析(二十七)--- rio系统I/O的封装
    下一篇:Redis源码分析(二十九)--- bio后台I/O服务的实现


    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    阿里云
    阿里云

    Archiver|手机版|小黑屋|Redis中国用户组 ( 京ICP备15003959号

    GMT+8, 2017-6-23 13:13 , Processed in 0.113260 second(s), 33 queries .

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

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