redis源码分析(二)-rio(读写抽象层)
Redis io抽象层
Redis中涉及到多种io,如socket与file,为了统一对它们的操作,redis设计了一个抽象层,即rio,使用rio可以实现将数据写入到不同的底层io,但是接口相同。rio的实现在rio.h与rio.c源文件中,支持内存、文件、socket集合三类底层io。
1. struct rio
struct rio中声明了统一的io操作接口,并且包含一个底层io对象的union结构。使用不同的底层io初始化rio实例后,调用rio的抽象接口即会调用对应底层io的实现。以面向对象的思想即是,rio为抽象类,它拥有三个子类:buffer、file及fdset,这三个子类实现了抽象类声明的接口。使用者可以使用它们的父类rio进行编程,实现多态性。
以下是struct rio中抽象接口的声明(此处省略了一些其它的成员):
struct _rio {
/* Backend functions.
* Since this functions do not tolerate short writes or reads the return
* value is simplified to: zero on error, non zero on complete success. */
size_t (*read)(struct _rio *, void *buf, size_t len);
size_t (*write)(struct _rio *, const void *buf, size_t len);
off_t (*tell)(struct _rio *);
int (*flush)(struct _rio *);
/* The update_cksum method if not NULL is used to compute the checksum of
* all the data that was read or written so far. The method should be
* designed so that can be called with the current checksum, and the buf
* and len fields pointing to the new block of data to add to the checksum
* computation. */
void (*update_cksum)(struct _rio *, const void *buf, size_t len);
...
/* Backend-specific vars. */
...
};
每一个底层对象都需要实现它需要支持的接口,实例化rio时,rio结构中的函数指针将指向底io的实现。Redis是C语言实现,因此针对 三个底层io声明了三个对应的初始化函数:
void rioInitWithFile(rio *r, FILE *fp);
void rioInitWithBuffer(rio *r, sds s);
void rioInitWithFdset(rio *r, int *fds, int numfds);
这三个函数将初始化rio实例中的函数指针为它对应的抽象接口实现,并初始化union结构指向正确的底层io对象。
注意:rio接口中虽然声明了write操作与read操作,但是redis中仅将它们用于单向操作,即一个rio实例或者使用write操作,或者使用read操作,同一个rio实例不能既读又写。
2. buffer
以buffer为底层io的rio实例,write操作将参数buf中的数据copy到一个sds中(redis的字符串实现)。反之,它的read操作将会从一个sds中读取数据到参数buf指向的地址中。
抽象接口不支持seek操作,因此写操作仅能append,而读操作也只能从当前位置读数据。buffer对象的结构声明如下:
/* In-memory buffer target. */
struct {
sds ptr;
off_t pos;
} buffer;
这里的pos记录了读写操作在buffer中的当前位置。
3. file
以file为底层io的rio实例,write操作将参数buf中的数据写入到文件中,而read操作则将file中的数据读到参数buf指向的内存地址中。file对象的抽象接口实现只需要简单的调用c语言的库函数即可。
同样由于抽象接口未声明seek操作,它的具体实现也没有实现seek操作。file对象的结构声明如下:
/* Stdio file pointer target. */
struct {
FILE *fp;
off_t buffered; /* Bytes written since last fsync. */
off_t autosync; /* fsync after 'autosync' bytes written. */
} file;
这里的buffered记录了写操作的累计数据量,而autosync为设置一个同步值,当buffered值超过autosync值后,会执行sync操作使数据同步到磁盘上,sync操作后将buffered值清零。
4. fdset
以fdset为底层io的rio实例可以同时将数据向多个目标写,在redis中主要用作master向它的多个slave发送同步数据,即使用fdset的write操作可以将一份数据向多个socket发送。对fdset的抽象大大地简化了redis的master向它的多个slave发送同步数据的 io操作
fdset不支持read操作。此外,它使用了类似buffer的一个sds实例作为缓存,数据首先被写入到该缓存中,当缓存中的数据超过一定数量,或者调用了flush操作,再将缓存中的数据发送到所有的socket中。fdset的结构声明如下:
/* Multiple FDs target (used to write to N sockets). */
struct {
int *fds; /* File descriptors. */
int *state; /* Error state of each fd. 0 (if ok) or errno. */
int numfds;
off_t pos;
sds buf;
} fdset;
fds即所有的目标socket的文件描述符集合,state记录了这些文件描述符的状态(是否发生写错误),numfds记录了集合的大小,buf为缓存,pos代表buf中下一个应该发送的数据的位置。
redis源码分析(二)-rio(读写抽象层)的更多相关文章
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...
- redis源码分析之事务Transaction(下)
接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令. 原文地址:http://www.jianshu.com/p/e22615586595 看本篇文章前需 ...
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- Vue源码分析(二) : Vue实例挂载
Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...
- 框架-springmvc源码分析(二)
框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...
- Redis源码分析:serverCron - redis源码笔记
[redis源码分析]http://blog.csdn.net/column/details/redis-source.html Redis源代码重要目录 dict.c:也是很重要的两个文件,主要 ...
- Tomcat源码分析二:先看看Tomcat的整体架构
Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...
- 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>
目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...
- ZRender源码分析4:Painter(View层)-中
回顾 上一篇说到:ZRender源码分析3:Painter(View层)-上,接上篇,开始Shape对象 总体理解 先回到上次的Painter的render方法 /** * 首次绘图,创建各种dom和 ...
随机推荐
- 使用s3-sftp-proxy 暴露minio s3 数据为sftp 访问
尽管s3 很不错,但是ftp 也有自己存在的价值,以下是一个简单的通过s3-sftp-proxy 暴露minio s3 数据为ftp 的访问方式 环境准备 docker-compose 文件 vers ...
- Javascript的数据类型(原始类型和引用类型)
1.ECMAScript3中定义了变量可分为原始值和引用值. 原始值:是保存在栈(stack)中的简单数据段:也就是说他们的值是直接存储在变量访问的位置. 引用值:是保存在堆(heap)中的对象,也就 ...
- 【JZOJ6233】【20190627】心的旋律
题目 你需要构造一个\(n\)个点的二分图 定义\(F(A)\)表示左部点集\(A\)能够到达的右部中的点 使得满足 $ F(A) \lt |A| $ 的集合恰好有 $ k $ 个 \(1 \le n ...
- vue-cli配置跨域代理
现在使用vue大多使用了前后端分离模式,因此游览器经常显示跨域失败的信息,现在跨域的方式很多种,主要分两大类,ajax跨域,dom跨域,具体的方法就不例举啦. vue-cli作为一个强大的脚手架,内置 ...
- X86 下的SSDT HOOK
目录 SSDTHOOK 1.SSDTHOOK 原理. 1.x32下的SSDT HOOK 2.SSDT HOOK代码 3.结果 4.总结 SSDTHOOK 1.SSDTHOOK 原理. x32下,直接获 ...
- 【CSP膜你赛】大逃亡
题目描述 魔王撒旦为了建立魔物的乐土,率领亚多拉玛雷克.艾谢尔.路西菲尔.以 及马纳果达这四位恶魔大元帅进攻人类世界.然而此时手持圣剑的勇者艾米莉亚出现了. 战败的魔王逃跑时穿越到了地球,以真奥贞夫 ...
- Mercurial 的hook使用
1. Handling repository events with hooks可以通过Mercurial版本管理工具提供的hooks机制来处理repo的各种事件,从而实现对Mercurial的扩展, ...
- 部署oVirt4.2+Gluster超融合架构
首先下载最新ovirt-node iso镜像 准备3台机器,配置为2核,16G内存,两块硬盘,1块100G装系统,1块300G做存储 node1.com(192.168.105.221) node2. ...
- [原创]STAR法则
[原创]STAR法则 STAR法则是情境(situation).任务(task).行动(action).结果(result)四项的缩写. STAR法则是一种常常被面试官使用的工具,用来收集面试者与工作 ...
- 第08组 Beta冲刺(3/4)
队名 八组评分了吗 组长博客链接(2分) 组员1李昕晖(组长) 过去两天完成了哪些任务 文字/口头描述 了解各个小组的进度与难以攻破的地方,晚上安排开会,安排新的冲刺任务. 重新分配小组及个人任务. ...