Redis 2.8.9源码 - rio模块

本文为作者原创,转载请注明出处:http://my.oschina.net/fuckphp/blog/349210

本文代码可以在 src/rio.h 和 src/rio.c 两个文件中找到。

redis中rio模块封装了Redis对文件读写和buffer读写的相关操作,Redis内部实现中,Rdb,Aof等都是基于该模块开发。

下面介绍一些rio的用法。

rio对象(如下代码定义在 src/rio.h 中)

关于文件读写操作和buffer的操作主要基于rio对象的操作,下面为rio对的定义

struct _rio {
    //读操作的回调函数 返回0 表示异常
    size_t (*read)(struct _rio *, void *buf, size_t len);
    //写操作的回调函数 返回0 表示异常
    size_t (*write)(struct _rio *, const void *buf, size_t len);
    //返回文件指针偏移位置
    off_t (*tell)(struct _rio *); 
    //计算当前已读或者已写数据的crc64校验值
    void (*update_cksum)(struct _rio *, const void *buf, size_t len);

    //当前校验值
    uint64_t cksum;
    //已读或者已写的字节数
    size_t processed_bytes;
    //每次写操作处理的最大长度
    size_t max_processing_chunk;

    union {
        struct {
            //buffer指针
            sds ptr;
            //当前的偏移量
            off_t pos;
        } buffer;
        struct {
            //打开的文件描述符
            FILE *fp;
            //最近一次fsync后写入的字节数
            off_t buffered; /* Bytes written since last fsync. */
            //多少字节进行一次fsync
            off_t autosync; /* fsync after 'autosync' bytes written. */
        } file;
    } io; 
};

了解了rio对象后,接下来介绍 buffer 和 文件 读写操作

buffer rio的初始化:

//buffer rio对象的初始化默认值
static const rio rioBufferIO = {
    rioBufferRead,  //设置读取操作函数
    rioBufferWrite, //设置写入操作函数
    rioBufferTell,  //获取 偏移量的函数
    NULL,           /* update_checksum */
    0,              /* current checksum */
    0,              /* bytes read or written */
    0,              /* read/write chunk size */
    { { NULL, 0 } } /* union for io-specific vars */
};
//使用 一个 sds 对象来初始化一个rio对象
void rioInitWithBuffer(rio *r, sds s) {
    //初始化buffer rio对象
    *r = rioBufferIO;
    //初始化 buffer 的值
    r->io.buffer.ptr = s;
    //偏移量初始化为 buffer 开头
    r->io.buffer.pos = 0;
}

File rio 的初始化:

//file rio对象的初始化默认值
static const rio rioFileIO = {
    rioFileRead,    //读取操作函数
    rioFileWrite,   //写入操作函数
    rioFileTell,    //获取偏移量
    NULL,           /* update_checksum */
    0,              /* current checksum */
    0,              /* bytes read or written */
    0,              /* read/write chunk size */
    { { NULL, 0 } } /* union for io-specific vars */
};
//初始化函数
void rioInitWithFile(rio *r, FILE *fp) {
    //设置rio对象默认值
    *r = rioFileIO;
    r->io.file.fp = fp;       //初始化文件描述符
    r->io.file.buffered = 0;  //初始化读写字节数
    r->io.file.autosync = 0;  //初始化默认为不自动fsync
}

  设置自动fsync操作:

void rioSetAutoSync(rio *r, off_t bytes) {
    //设置断言来控制只有文件操作才允许设置
    redisAssert(r->read == rioFileIO.read);
    //设置每写入多少字节进行一次fsync操作(合理的控制该数字可以降低io压力)
    r->io.file.autosync = bytes;
}

执行rio的写操作:

//rio对象写入操作
static inline size_t rioWrite(rio *r, const void *buf, size_t len) {
    while (len) {
        //设置每次写入的字节数 对数据进行分块写入
        size_t bytes_to_write = (r->max_processing_chunk && r->max_processing_chunk < len) ? r->max_processing_chunk : len;
        //计算并更新校验和
        if (r->update_cksum) r->update_cksum(r,buf,bytes_to_write);
        //执行 bytes_to_write 长度的写操作 调用上文注册的回调函数
        if (r->write(r,buf,bytes_to_write) == 0)
            return 0;
        //设置额写入位置的指针
        buf = (char*)buf + bytes_to_write;
        //剩余未处理长度
        len -= bytes_to_write;
        //记录已经写入的字节数
        r->processed_bytes += bytes_to_write;
    }
    return 1;
}
//buffer的写操作回调函数
static size_t rioBufferWrite(rio *r, const void *buf, size_t len) {
    //在buffer rio的 sds对象ptr的结尾追加字符串
    r->io.buffer.ptr = sdscatlen(r->io.buffer.ptr,(char*)buf,len);
    //更新当前操作的指针偏移量
    r->io.buffer.pos += len;
    return 1;
}
//file的写操作回调函数
static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
    size_t retval;
    //向文件描述符中写入指定字节的字符串
    retval = fwrite(buf,len,1,r->io.file.fp);
    //记录已写入的字节数
    r->io.file.buffered += len;
    //如果已经写入的字节数倒带autosync要求的字节数则进行flush操作
    if (r->io.file.autosync &&
        r->io.file.buffered >= r->io.file.autosync)
    {
        //将数据刷新同步到硬盘中
        fflush(r->io.file.fp);
        //如果 src/config.h中 定义该宏所调用的函数
        aof_fsync(fileno(r->io.file.fp));
        //设置已写字符数为0
        r->io.file.buffered = 0;
    }
    return retval;
}

读取与写入操作相似,就不进行过多叙述。

另外redis的 rio中还封装了 一些生成aof 协议的函数:

size_t rioWriteBulkCount(rio *r, char prefix, int count);
size_t rioWriteBulkString(rio *r, const char *buf, size_t len);
size_t rioWriteBulkLongLong(rio *r, long long l);
size_t rioWriteBulkDouble(rio *r, double d);

这些操作将在之后的笔记中揭晓(因为我还没看到那里)。





Redis2.8.9源码   src/rio.h   src/rio.c

你可能感兴趣的:(redis,AOF,RDB,redis源码,rio)