redis object对象系统的源码分析

        redis中实现很多数据结构来存储键值对,主要有简单动态字符串、双端队列、字典、压缩列表、整数集合和跳跃表。但是使用也是基于这些数据结构构建看一个对象系统,主要是字符串对象、列表对象、哈希对象、集合对象和有序集合对象,每种对象都用到至少一种上述的数据结构。

       在object.c主要是实现了对象的创建、引用计数和释放,字符串对象的编码转换。

对象的结构体

typedef struct redisObject {
    unsigned type:4;//对象类型
    unsigned encoding:4;//对象的编码类型
    unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;//对象的引用计数
    void *ptr;//指向对象内容的指针
} robj;

对象的五种类型

#define OBJ_STRING 0//字符串对象
#define OBJ_LIST 1//列表对象
#define OBJ_SET 2//集合对象
#define OBJ_ZSET 3//有序集合对象
#define OBJ_HASH 4//哈希对象

    对象的编码

#define OBJ_ENCODING_RAW 0//简单动态字符串——字符串对象
#define OBJ_ENCODING_INT 1//long类型整数——字符串对象
#define OBJ_ENCODING_HT 2//字典——散列对象和集合对象
#define OBJ_ENCODING_ZIPMAP 3//压缩图
#define OBJ_ENCODING_LINKEDLIST 4 //双端列表——列表对象
#define OBJ_ENCODING_ZIPLIST 5 //压缩列表——有序集合对象
#define OBJ_ENCODING_INTSET 6 //整数集合——集合对象
#define OBJ_ENCODING_SKIPLIST 7 //跳跃表——有序集合对象
#define OBJ_ENCODING_EMBSTR 8 //embstr编码的简单动态字符串——字符串对象
#define OBJ_ENCODING_QUICKLIST 9 //基于压缩列表的双端列表——列表对象	

一、对象的创建

       基本对象创建函数,创建robj结构体,指定类型和对象内容,编码初始化为OBJ_ENCODING_RAW,泛化的对象创建函数需要重新设定自己的编码。

robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->encoding = OBJ_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;
    /* Set the LRU to the current lruclock (minutes resolution). */
    o->lru = LRU_CLOCK();
    return o;
}

      五种对象的创建函数

//根据字符串长度选择使用OBJ_ENCODING_EMBSTR还是OBJ_ENCODING_RAW创建字符串对象
robj *createStringObject(const char *ptr, size_t len) {
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}
robj *createEmbeddedStringObject(const char *ptr, size_t len);//创建OBJ_ENCODING_EMBSTR编码的字符串对象
robj *createRawStringObject(const char *ptr, size_t len);//封装createObject创建OBJ_ENCODING_RAW编码的列表对象
robj *createQuicklistObject(void);//封装createObject创建OBJ_ENCODING_QUICKLIST编码的列表对象
robj *createZiplistObject(void);//封装createObject创建OBJ_ENCODING_ZIPLIST编码的列表对象
robj *createSetObject(void);//封装createObject创建OBJ_ENCODING_HT编码的集合对象
robj *createIntsetObject(void);//封装createObject创建OBJ_ENCODING_INTSET编码的集合对象
robj *createHashObject(void);//封装createObject创建OBJ_ENCODING_ZIPLIST编码的散列对象
robj *createZsetObject(void);//封装createObject创建OBJ_ENCODING_ZIPLIST编码的有序集合对象
robj *createZsetZiplistObject(void);//封装createObject创建OBJ_ENCODING_ZIPLIST编码的有序集合对象

二、对象的引用计数和释放

     对象的引用计数主要是为了更好的管理对象,及时的释放掉对象不用的内存。

void incrRefCount(robj *o) {//引用计数增加函数
    if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount++;
}//引用计数减少函数
void decrRefCountVoid(void *o) {
    decrRefCount(o);
}
//引用计数减少函数,当计数为1是调用,释放对象。
void decrRefCount(robj *o) {
    if (o->refcount == 1) {
        switch(o->type) {//根据类型不同选择不同释放函数
        case OBJ_STRING: freeStringObject(o); break;
        case OBJ_LIST: freeListObject(o); break;
        case OBJ_SET: freeSetObject(o); break;
        case OBJ_ZSET: freeZsetObject(o); break;
        case OBJ_HASH: freeHashObject(o); break;
        default: serverPanic("Unknown object type"); break;
        }
        zfree(o);
    } else {
        if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
        if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
    }
}//重置对象引用计数
robj *resetRefCount(robj *obj) {
    obj->refcount = 0;
    return obj;
}

       对象释放函数

void freeStringObject(robj *o); //释放字符串对象的内容,o->ptr
void freeListObject(robj *o); //释放列表对象的内容,o->ptr 
void freeSetObject(robj *o); //释放集合对象的内容,o->ptr 
void freeZsetObject(robj *o); //释放有序集合对象的内容,o->ptr
void freeHashObject(robj *o);//释放散列对象的内容,o->ptr

三、对象的编码转换

//对字符串对象进行节省空间的编码转换
robj *tryObjectEncoding(robj *o) {
    long value;
    sds s = o->ptr;
    size_t len;
    //OBJ_ENCODING_INT编码的对象不需要编码转换
    if (!sdsEncodedObject(o)) return o;
    //引用计数大于1的字符串对象不能进行编码转换
     if (o->refcount > 1) return o;
    len = sdslen(s);
    if (len <= 21 && string2l(s,len,&value)) {
        //内容为长度小于21的数字字符串的字符串对象
        if ((server.maxmemory == 0 ||
             (server.maxmemory_policy != MAXMEMORY_VOLATILE_LRU &&
              server.maxmemory_policy != MAXMEMORY_ALLKEYS_LRU)) &&
            value >= 0 &&
            value < OBJ_SHARED_INTEGERS)
        {/*当内存策略不是lru或没有可使用内存和数字介于
        0~OBJ_SHARED_INTEGERS使用共享整数字符串,不改变编码*/
            decrRefCount(o);
            incrRefCount(shared.integers[value]);
            return shared.integers[value];
        } else {//编码转换成OBJ_ENCODING_INT
            if (o->encoding == OBJ_ENCODING_RAW) sdsfree(o->ptr);
            o->encoding = OBJ_ENCODING_INT;
            o->ptr = (void*) value;
            return o;
        }
    }
    //字符串长度小于OBJ_ENCODING_EMBSTR_SIZE_LIMIT,编码转换成OBJ_ENCODING_EMBSTR
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT,编码转换成) {
        robj *emb;
        if (o->encoding == OBJ_ENCODING_EMBSTR) return o;
        emb = createEmbeddedStringObject(s,sdslen(s));
        decrRefCount(o);
        return emb;
    }
    //编码为OBJ_ENCODING_RAW,sds的可用大小大于len/10,释放掉可用空间
    if (o->encoding == OBJ_ENCODING_RAW &&
        sdsavail(s) > len/10)
    {
        o->ptr = sdsRemoveFreeSpace(o->ptr);
    }
    return o;
}
//将OBJ_ENCODING_INT编码字符串转成OBJ_ENCODING_EMBSTR或者OBJ_ENCODING_RAW
robj *getDecodedObject(robj *o) {
    robj *dec;
    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");
    }
}



 


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值