Redis的String源码分析

Redis的字符串类型是其数据操作的基础,采用redisObject结构体表示,支持int和raw编码。文章介绍了SET、GET、APPEND和STRLEN等字符串操作函数的实现细节,强调了字符串在Redis中的二进制安全性及其高效管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis的字符串类型是实现的基础,因为在Redis中几乎所有的数据都是以字符串的形式存储和操作的。在Redis中,字符串被看作是二进制安全的字符数组,这意味着字符串可以包含任何数据,包括空字节。

Redis字符串类型的实现包括以下三个部分:

  1. 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;
  1. 编码方式

Redis支持两种编码方式:int编码和raw编码。int编码是指将整数类型的值作为字符串存储,raw编码是指将字符串作为字符数组存储。

int编码只能用于比较小的整数,因为在较大的整数上使用int编码将占用太多的内存。在Redis中,当字符串的长度小于等于39字节并且可以转换为long,long类型时,字符串将使用int编码,否则将使用raw编码。

  1. 字符串操作函数

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对字符串类型进行高效的存储和操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值