简介
redisObjet其实就是对应用类型的封装。简介面向对象的思想。实现对数据的统一管理保存
数据结构
typedef struct redisObject {
unsigned type:4; //保存信息的类型
unsigned encoding:4;//保存信息的编码方式
unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;//引用次数
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;//设置编码
o->ptr = ptr;//保存指针
o->refcount = 1;//设置引用计数
/* 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); //创建一个共享的对象
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); //分配内存空间
struct sdshdr8 *sh = (void*)(o+1);//找到内存地址
o->type = OBJ_STRING;//设置类型
o->encoding = OBJ_ENCODING_EMBSTR;//编码
o->ptr = sh+1;//偏移
o->refcount = 1;//设置引用计数
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) {//拷贝内存
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++;//增加引用计数
}
void decrRefCount(robj *o) {//减少引用计数
if (o->refcount == 1) {//引用计数为0释放对象
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;
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;//是不是编码的数据 排除掉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)) {//是一个数字
/* 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;//设置为int保存
o->ptr = (void*) value;//使用指针的内存来保存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));//转换成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保存的数据解码出来
incrRefCount(o);
return o;
}
if (o->type == OBJ_STRING && o->encoding == OBJ_ENCODING_INT) {
char buf[32];
ll2string(buf,32,(long)o->ptr);//转成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;//内存地址一样 没啥说的
if (sdsEncodedObject(a)) {
astr = a->ptr;
alen = sdslen(astr);
} else {
alen = ll2string(bufa,sizeof(bufa),(long) a->ptr);//把使用数字保存的解码出来
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);//内存比较
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){//对于两个都是数字保存的 直接比较值
/* 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;//否则使用内存比较
}
}
/* 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) {//对于内存保存的
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 分配的个数
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);//来来继续算个大概值
} 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的大小 因为是随机来的 对应一个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;
}
这里的话没有什么新东西。随意看下就好。