Redis的字符串类型是实现的基础,因为在Redis中几乎所有的数据都是以字符串的形式存储和操作的。在Redis中,字符串被看作是二进制安全的字符数组,这意味着字符串可以包含任何数据,包括空字节。
Redis字符串类型的实现包括以下三个部分:
redisObject
结构体
RedisObject
结构体是Redis
中所有数据类型的通用结构体,它包括一个类型字段和一个指向实际值的指针。对于字符串类型,实际值是一个char
数组。
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
- 编码方式
Redis支持两种编码方式:int
编码和raw
编码。int
编码是指将整数类型的值作为字符串存储,raw
编码是指将字符串作为字符数组存储。
int
编码只能用于比较小的整数,因为在较大的整数上使用int编码将占用太多的内存。在Redis中,当字符串的长度小于等于39字节并且可以转换为long
,long
类型时,字符串将使用int
编码,否则将使用raw
编码。
- 字符串操作函数
Redis提供了一组字符串操作函数,这些函数包括基本的字符串操作,如设置、获取、修改、连接等。
以下是一些字符串操作函数的实现:
SET
命令
SET
命令用于设置一个key
的值为一个字符串。SET
命令实现的主要思路是根据编码方式的不同,分别进行处理。
void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expire, int unit) {
long long milliseconds = 0;
if (expire) {
if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
return;
if (milliseconds <= 0) {
addReplyError(c,"invalid expire time in SETEX");
return;
}
if (unit == UNIT_SECONDS) milliseconds *= 1000;
}
if (nx && lookupKeyWrite(c->db,key) != NULL) {
addReply(c, shared.czero);
return;
}
setKey(c->db,key,val);
server.dirty++;
if (expire) setExpire(c->db,key,mstime()+milliseconds);
addReply(c, nx ? shared.cone : shared.ok);
}
GET
命令
GET
命令用于获取一个key
的值。GET
命令实现的主要思路是查找key
,然后返回key
的值。
void getCommand(redisClient *c) {
robj *o;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
return;
if (o->type != OBJ_STRING) {
addReply(c,shared.wrongtypeerr);
return;
}
addReplyBulk(c,o);
}
APPEND
命令
APPEND
命令用于在一个key
的值后面追加一个字符串。APPEND
命令实现的主要思路是先查找key
,然后检查key
的类型是否为字符串类型,然后将要追加的字符串和原字符串连接起来,并更新key
的值。
void appendCommand(redisClient *c) {
size_t totlen;
robj *o, *append;
o = lookupKeyWrite(c->db,c->argv[1]);
if (o == NULL) {
/* Create the key */
c->db->dict = dictCreate(&dbDictType,NULL);
o = createStringObject("",0);
dictAdd(c->db->dict,c->argv[1],o);
incrRefCount(c->argv[1]);
} else {
if (o->type != OBJ_STRING) {
addReply(c,shared.wrongtypeerr);
return;
}
}
append = c->argv[2];
if (sdslen(append->ptr) > 0) {
o->ptr = sdscatlen(o->ptr,append->ptr,sdslen(append->ptr));
totlen = sdslen(o->ptr);
signalModifiedKey(c,c->db,c->argv[1]);
server.dirty++;
} else {
totlen = sdslen(o->ptr);
}
addReplyLongLong(c,totlen);
}
STRLEN
命令
STRLEN
命令用于获取一个key
的值的长度。STRLEN
命令实现的主要思路是先查找key
,然后检查key
的类型是否为字符串类型,然后返回字符串的长度。
void strlenCommand(redisClient *c) {
robj *o;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,o,OBJ_STRING)) return;
addReplyLongLong(c,sdslen(o->ptr));
}
以上是Redis字符串类型的一些基本操作函数的实现。Redis字符串类型的源码比较简单,主要就是对字符串的编码方式、存储和操作进行了封装,方便Redis对字符串类型进行高效的存储和操作。