redis object对象系统的源码分析

来源:互联网 发布:Execl数据分析证书 编辑:程序博客网 时间:2024/05/01 19:19
        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->ptrvoid freeListObject(robj *o); //释放列表对象的内容,o->ptr void freeSetObject(robj *o); //释放集合对象的内容,o->ptr void freeZsetObject(robj *o); //释放有序集合对象的内容,o->ptrvoid 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_RAWrobj *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");    }}







0 0