Redis redisObject

簡介

redisObjet其實就是對應(yīng)用類型的封裝。簡介面向?qū)ο蟮乃枷搿崿F(xiàn)對數(shù)據(jù)的統(tǒng)一管理保存

數(shù)據(jù)結(jié)構(gòu)

typedef struct redisObject {
    unsigned type:4; //保存信息的類型
    unsigned encoding:4;//保存信息的編碼方式
    unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;//引用次數(shù)
    void *ptr;//保存的指針
} robj;
/* Object types */
#define OBJ_STRING 0
#define OBJ_LIST 1
#define OBJ_SET 2
#define OBJ_ZSET 3
#define OBJ_HASH 4

/* Objects encoding. Some kind of objects like Strings and Hashes can be
 * internally represented in multiple ways. The 'encoding' field of the object
 * is set to one of this fields for this object. */
#define OBJ_ENCODING_RAW 0     /* Raw representation */
#define OBJ_ENCODING_INT 1     /* Encoded as integer */
#define OBJ_ENCODING_HT 2      /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6  /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7  /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8  /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */

這一塊特別簡單,type表示保存的類型蘸际。encode表示保存的方式。兩個就可以確定我們的object;

基本的方法

robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));//分配一個robj的空間
    o->type = type;//保存type
    o->encoding = OBJ_ENCODING_RAW;//設(shè)置編碼
    o->ptr = ptr;//保存指針
    o->refcount = 1;//設(shè)置引用計數(shù)

    /* Set the LRU to the current lruclock (minutes resolution), or
     * alternatively the LFU counter. */
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
    } else {
        o->lru = LRU_CLOCK();
    }
    return o;
}

robj *makeObjectShared(robj *o) {
    serverAssert(o->refcount == 1); //創(chuàng)建一個共享的對象
    o->refcount = OBJ_SHARED_REFCOUNT;
    return o;
}

robj *createEmbeddedStringObject(const char *ptr, size_t len) {
    robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1); //分配內(nèi)存空間
    struct sdshdr8 *sh = (void*)(o+1);//找到內(nèi)存地址

    o->type = OBJ_STRING;//設(shè)置類型
    o->encoding = OBJ_ENCODING_EMBSTR;//編碼
    o->ptr = sh+1;//偏移
    o->refcount = 1;//設(shè)置引用計數(shù)
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
    } else {
        o->lru = LRU_CLOCK();
    }

    sh->len = len;//長度
    sh->alloc = len;
    sh->flags = SDS_TYPE_8;//sds類型
    if (ptr) {//拷貝內(nèi)存
        memcpy(sh->buf,ptr,len);
        sh->buf[len] = '\0';
    } else {
        memset(sh->buf,0,len+1);
    }
    return o;
}


/* Create a string object with EMBSTR encoding if it is smaller than
 * REIDS_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
 * used.
 *
 * The current limit of 39 is chosen so that the biggest string object
 * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
    //sizeof(redisObject) = 16 
    //sizeof(sdshdr8) = 3
    //一個 \0 =1
    //就只剩下44了
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}

引用的操作

void incrRefCount(robj *o) {
    if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount++;//增加引用計數(shù)
}

void decrRefCount(robj *o) {//減少引用計數(shù)
    if (o->refcount == 1) {//引用計數(shù)為0釋放對象
        switch(o->type) {//
        case OBJ_STRING: freeStringObject(o); break;//各個對象對應(yīng)的釋放方法
        case OBJ_LIST: freeListObject(o); break;
        case OBJ_SET: freeSetObject(o); break;
        case OBJ_ZSET: freeZsetObject(o); break;
        case OBJ_HASH: freeHashObject(o); break;
        case OBJ_MODULE: freeModuleObject(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--;
    }
}

一些輔助操作

/* 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);//確定是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;//是不是編碼的數(shù)據(jù) 排除掉int那些

    /* 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. */
     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. */
    len = sdslen(s);//獲取長度
    if (len <= 20 && string2l(s,len,&value)) {//是一個數(shù)字
        /* 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. */
        if ((server.maxmemory == 0 ||
            !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
            value >= 0 &&
            value < OBJ_SHARED_INTEGERS)
        {
            decrRefCount(o);//釋放原來的對象
            incrRefCount(shared.integers[value]);//使用共享對象
            return shared.integers[value];
        } else {
            if (o->encoding == OBJ_ENCODING_RAW) sdsfree(o->ptr);//釋放這個字符串
            o->encoding = OBJ_ENCODING_INT;//設(shè)置為int保存
            o->ptr = (void*) value;//使用指針的內(nèi)存來保存value
            return o;
        }
    }

    /* 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. */
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
        robj *emb;

        if (o->encoding == OBJ_ENCODING_EMBSTR) return o;
        emb = createEmbeddedStringObject(s,sdslen(s));//轉(zhuǎn)換成emb
        decrRefCount(o);
        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.
     *
     * 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. */
    if (o->encoding == OBJ_ENCODING_RAW &&
        sdsavail(s) > len/10)//空間利用率太低
    {
        o->ptr = sdsRemoveFreeSpace(o->ptr);//釋放下多余的空間
    }

    /* Return the original object. */
    return o;
}
robj *getDecodedObject(robj *o) {
    robj *dec;

    if (sdsEncodedObject(o)) {//對于int保存的數(shù)據(jù)解碼出來
        incrRefCount(o);
        return o;
    }
    if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) {
        char buf[32];

        ll2string(buf,32,(long)o->ptr);//轉(zhuǎn)成string
        dec = createStringObject(buf,strlen(buf));
        return dec;
    } else {
        serverPanic("Unknown encoding type");
    }
}

#define REDIS_COMPARE_BINARY (1<<0)
#define REDIS_COMPARE_COLL (1<<1)

int compareStringObjectsWithFlags(robj *a, robj *b, int flags) {//string 不叫
    serverAssertWithInfo(NULL,a,a->type == OBJ_STRING && b->type == OBJ_STRING);//必須兩個都是string
    char bufa[128], bufb[128], *astr, *bstr;
    size_t alen, blen, minlen;

    if (a == b) return 0;//內(nèi)存地址一樣 沒啥說的
    if (sdsEncodedObject(a)) { 
        astr = a->ptr;
        alen = sdslen(astr);
    } else {
        alen = ll2string(bufa,sizeof(bufa),(long) a->ptr);//把使用數(shù)字保存的解碼出來
        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);//使用strcoll比較
    } else {
        int cmp;

        minlen = (alen < blen) ? alen : blen;//最短的
        cmp = memcmp(astr,bstr,minlen);//內(nèi)存比較
        if (cmp == 0) return alen-blen;
        return cmp;
    }
}
int equalStringObjects(robj *a, robj *b) {//
    if (a->encoding == OBJ_ENCODING_INT &&
        b->encoding == OBJ_ENCODING_INT){//對于兩個都是數(shù)字保存的 直接比較值
        /* 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;//否則使用內(nèi)存比較
    }
}

/* Returns the size in bytes consumed by the key's value in RAM.
 * Note that the returned value is just an approximation, especially in the
 * case of aggregated data types where only "sample_size" elements
 * are checked and averaged to estimate the total size. */
#define OBJ_COMPUTE_SIZE_DEF_SAMPLES 5 /* Default sample size. */
size_t objectComputeSize(robj *o, size_t sample_size) {//這個玩意是返回個大概值 aggregated data types 他最多便利sample_size 個然后再來整個平均值
    sds ele, ele2;
    dict *d;
    dictIterator *di;
    struct dictEntry *de;
    size_t asize = 0, elesize = 0, samples = 0;

    if (o->type == OBJ_STRING) {
        if(o->encoding == OBJ_ENCODING_INT) {//對于值的保存沒有使用額外的空間
            asize = sizeof(*o);
        } else if(o->encoding == OBJ_ENCODING_RAW) {//對于內(nèi)存保存的
            asize = sdsAllocSize(o->ptr)+sizeof(*o);//加上額外的string空間
        } else if(o->encoding == OBJ_ENCODING_EMBSTR) {
            asize = sdslen(o->ptr)+2+sizeof(*o);//多余的兩個頭信息
        } else {
            serverPanic("Unknown string encoding");
        }
    } else if (o->type == OBJ_LIST) {
        if (o->encoding == OBJ_ENCODING_QUICKLIST) {
            quicklist *ql = o->ptr;
            quicklistNode *node = ql->head;
            asize = sizeof(*o)+sizeof(quicklist);//quicklist本身的長度 加上robjet的長度
            do {
                elesize += sizeof(quicklistNode)+ziplistBlobLen(node->zl);//加上node本身的長度和ziplist的長度
                samples++;
            } while ((node = node->next) && samples < sample_size);//不一定會跑完哦
            asize += (double)elesize/samples*ql->len;//取個估計值 反正就是沒跑完
        } else if (o->encoding == OBJ_ENCODING_ZIPLIST) {
            asize = sizeof(*o)+ziplistBlobLen(o->ptr);//ziplist 直接拿
        } else {
            serverPanic("Unknown list encoding");
        }
    } else if (o->type == OBJ_SET) {//set
        if (o->encoding == OBJ_ENCODING_HT) {//是個hash
            d = o->ptr;
            di = dictGetIterator(d);//拉取遍歷 
            asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));//robject dict dictEntry* *slots 分配的個數(shù)
            while((de = dictNext(di)) != NULL && samples < sample_size) {
                ele = dictGetKey(de);//拉取key 不過我在setDictType 沒看到keydup 不過有個dictSdsDestructor 不過具體的set沒去看 
                elesize += sizeof(struct dictEntry) + sdsAllocSize(ele);//
                samples++;
            }
            dictReleaseIterator(di);
            if (samples) asize += (double)elesize/samples*dictSize(d);//來來繼續(xù)算個大概值
        } else if (o->encoding == OBJ_ENCODING_INTSET) {//intset
            intset *is = o->ptr;
            asize = sizeof(*o)+sizeof(*is)+is->encoding*is->length;//直接干
        } else {
            serverPanic("Unknown set encoding");
        }
    } else if (o->type == OBJ_ZSET) {//zset
        if (o->encoding == OBJ_ENCODING_ZIPLIST) {
            asize = sizeof(*o)+(ziplistBlobLen(o->ptr));//ziplist
        } else if (o->encoding == OBJ_ENCODING_SKIPLIST) {
            d = ((zset*)o->ptr)->dict;
            zskiplist *zsl = ((zset*)o->ptr)->zsl;
            zskiplistNode *znode = zsl->header->level[0].forward;
            asize = sizeof(*o)+sizeof(zset)+(sizeof(struct dictEntry*)*dictSlots(d));//基本大小
            while(znode != NULL && samples < sample_size) {
                elesize += sdsAllocSize(znode->ele);//保存對象的大小
                elesize += sizeof(struct dictEntry) + zmalloc_size(znode);//zone的大小 因為是隨機(jī)來的 對應(yīng)一個dictentry
                samples++;
                znode = znode->level[0].forward;
            }
            if (samples) asize += (double)elesize/samples*dictSize(d);//大概值
        } else {
            serverPanic("Unknown sorted set encoding");
        }
    } else if (o->type == OBJ_HASH) {
        if (o->encoding == OBJ_ENCODING_ZIPLIST) {
            asize = sizeof(*o)+(ziplistBlobLen(o->ptr));
        } else if (o->encoding == OBJ_ENCODING_HT) {
            d = o->ptr;
            di = dictGetIterator(d);
            asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
            while((de = dictNext(di)) != NULL && samples < sample_size) {
                ele = dictGetKey(de); //hash就有了兩個方法
                ele2 = dictGetVal(de);
                elesize += sdsAllocSize(ele) + sdsAllocSize(ele2);
                elesize += sizeof(struct dictEntry);
                samples++;
            }
            dictReleaseIterator(di);
            if (samples) asize += (double)elesize/samples*dictSize(d);
        } else {
            serverPanic("Unknown hash encoding");
        }
    } else if (o->type == OBJ_MODULE) {
        moduleValue *mv = o->ptr;
        moduleType *mt = mv->type;
        if (mt->mem_usage != NULL) {
            asize = mt->mem_usage(mv->value);
        } else {
            asize = 0;
        }
    } else {
        serverPanic("Unknown object type");
    }
    return asize;
}

這里的話沒有什么新東西。隨意看下就好衩辟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市波附,隨后出現(xiàn)的幾起案子艺晴,更是在濱河造成了極大的恐慌,老刑警劉巖掸屡,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件封寞,死亡現(xiàn)場離奇詭異,居然都是意外死亡仅财,警方通過查閱死者的電腦和手機(jī)狈究,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盏求,“玉大人抖锥,你說我怎么就攤上這事∷榉#” “怎么了磅废?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長荆烈。 經(jīng)常有香客問我拯勉,道長竟趾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任宫峦,我火速辦了婚禮岔帽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斗遏。我一直安慰自己山卦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布诵次。 她就那樣靜靜地躺著账蓉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逾一。 梳的紋絲不亂的頭發(fā)上铸本,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音遵堵,去河邊找鬼箱玷。 笑死,一個胖子當(dāng)著我的面吹牛陌宿,可吹牛的內(nèi)容都是我干的锡足。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼壳坪,長吁一口氣:“原來是場噩夢啊……” “哼舶得!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起爽蝴,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤沐批,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蝎亚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體九孩,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年发框,在試婚紗的時候發(fā)現(xiàn)自己被綠了躺彬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡梅惯,死狀恐怖宪拥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情个唧,我是刑警寧澤江解,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站徙歼,受9級特大地震影響犁河,放射性物質(zhì)發(fā)生泄漏鳖枕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一桨螺、第九天 我趴在偏房一處隱蔽的房頂上張望宾符。 院中可真熱鬧,春花似錦灭翔、人聲如沸魏烫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哄褒。三九已至,卻和暖如春煌张,著一層夾襖步出監(jiān)牢的瞬間呐赡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工骏融, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留链嘀,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓档玻,卻偏偏與公主長得像怀泊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子误趴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容