簡介
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;
}
這里的話沒有什么新東西。隨意看下就好衩辟。