Redis对象结构

object.c

object.c文件主要记录了Redis对象的创建和释放方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
robj *createEmbeddedStringObject(char *ptr, size_t len) {
robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr)+len+1);
struct sdshdr *sh = (void*)(o+1);

o->type = REDIS_STRING;
o->encoding = REDIS_ENCODING_EMBSTR;
o->ptr = sh+1;
o->refcount = 1;
o->lru = LRU_CLOCK();

sh->len = len;
sh->free = 0;
if (ptr) {
memcpy(sh->buf,ptr,len);
sh->buf[len] = '\0';
} else {
memset(sh->buf,0,len+1);
}
return o;
}

从这个函数中,我们可以看出Redis在创建一个REDIS_ENCODING_EMBSTR编码的字符串对象时,是SDS连同redisObject一同创建的。也就是说这个字符串是不可以修改的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
robj *createStringObjectFromLongLong(long long value) {

robj *o;

// value 的大小符合 REDIS 共享整数的范围
// 那么返回一个共享对象
if (value >= 0 && value < REDIS_SHARED_INTEGERS) {
incrRefCount(shared.integers[value]);
o = shared.integers[value];

// 不符合共享范围,创建一个新的整数对象
} else {
// 值可以用 long 类型保存,
// 创建一个 REDIS_ENCODING_INT 编码的字符串对象
if (value >= LONG_MIN && value <= LONG_MAX) {
o = createObject(REDIS_STRING, NULL);
o->encoding = REDIS_ENCODING_INT;
o->ptr = (void*)((long)value);

// 值不能用 long 类型保存(long long 类型),将值转换为字符串,
// 并创建一个 REDIS_ENCODING_RAW 的字符串对象来保存值
} else {
o = createObject(REDIS_STRING,sdsfromlonglong(value));
}
}

return o;
}

这个函数是根据传入的整数值来创建一个字符串对象。从这里可以看到主要有三个判断:

  1. 如果设置的值符合Redis共享整数对象的范围时,是直接复用共享对象,并不会去创建一个新的对象。
  2. 如果传入的值是long类型的,这创建一个REDIS_ENCODING_INT编码类型的字符串对象。
  3. 如果传入的值为long long类型的,则创建REDIS_ENCODING_RAW编码类型的字符串对象。

debug命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* Object command allows to inspect the internals of an Redis Object.
* Usage: OBJECT <verb> ... arguments ... */
void objectCommand(redisClient *c) {
robj *o;

// 返回对戏哪个的引用计数
if (!strcasecmp(c->argv[1]->ptr,"refcount") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
addReplyLongLong(c,o->refcount);

// 返回对象的编码
} else if (!strcasecmp(c->argv[1]->ptr,"encoding") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
addReplyBulkCString(c,strEncoding(o->encoding));

// 返回对象的空闲时间
} else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
addReplyLongLong(c,estimateObjectIdleTime(o)/1000);
} else {
addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime)");
}
}