Redis源代码分析(二十七)--- rio制I/O包裹
I/O每个操作系统,它的一个组成部分。和I/O业务质量,在一定程度上也影响了系统的效率。
今天,我在了解了Redis中间I/O的,相同的,Redis在他自己的系统中。也封装了一个I/O层。简称RIO。得先看看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 *);
/* 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); /* The current checksum */
/* 当前的校验和 */
uint64_t cksum; /* number of bytes read or written */
/* 当前读取的或写入的字节大小 */
size_t processed_bytes; /* maximum single read or write chunk size */
/* 最大的单次读写的大小 */
size_t max_processing_chunk; /* Backend-specific vars. */
/* rio中I/O变量 */
union {
//buffer结构体
struct {
//buffer详细内容
sds ptr;
//偏移量
off_t pos;
} buffer;
//文件结构体
struct {
FILE *fp;
off_t buffered; /* Bytes written since last fsync. */
//同步的最小大小
off_t autosync; /* fsync after 'autosync' bytes written. */
} file;
} io;
};
里面除了3个必须的方法,read,write方法,还有获取偏移量的tell方法。还有2个结构体变量。一个buffer结构体,一个file结构体。作者针对不同的I/O情况。做了不同的处理。当运行暂时的I/O操作时,都与rio.buffer打交道,当与文件进行I/O操作时。则运行与rio.file之间的操作。以下看看rio统一定义的读写方法:
/* The following functions are our interface with the stream. They'll call the
* actual implementation of read / write / tell, and will update the checksum
* if needed. */
/* 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);
//运行写方法
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;
} /* rio的读方法 */
static inline size_t rioRead(rio *r, void *buf, size_t len) {
while (len) {
//推断当前操作字节长度是否超过最大长度
size_t bytes_to_read = (r->max_processing_chunk && r->max_processing_chunk < len) ? r->max_processing_chunk : len;
//读数据方法
if (r->read(r,buf,bytes_to_read) == 0)
return 0;
//读数据时,更新校验和
if (r->update_cksum) r->update_cksum(r,buf,bytes_to_read);
buf = (char*)buf + bytes_to_read;
len -= bytes_to_read;
r->processed_bytes += bytes_to_read;
}
return 1;
}
这里有一个比較不错的地方。每次当有数据发生改变的时候,Redis都会做一个计算校验和的处理算法,表明了数据操作的改变动作,用的算法就是之前介绍过CRC64算法,针对RIO的buffer IO和File IO,Redis定义了2个RIO结构体:
/* 依据上面描写叙述的方法,定义了BufferRio */
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 */
}; /* 依据上面描写叙述的方法,定义了FileRio */
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 */
};
里面分别定义了相相应的读写方法,比方buffer的Read方法和File的Read方法:
/* Returns 1 or 0 for success/failure. */
/* 读取rio中的buffer内容到传入的參数 */
static size_t rioBufferRead(rio *r, void *buf, size_t len) {
if (sdslen(r->io.buffer.ptr)-r->io.buffer.pos < len)
return 0; /* not enough buffer to return len bytes. */
memcpy(buf,r->io.buffer.ptr+r->io.buffer.pos,len);
r->io.buffer.pos += len;
return 1;
}
/* Returns 1 or 0 for success/failure. */
/* 读取rio中的fp文件内容 */
static size_t rioFileRead(rio *r, void *buf, size_t len) {
return fread(buf,len,1,r->io.file.fp);
}
作用的rio的对象变量不一样,最后在Redis的声明中给出了4种不同类型数据的写入方法:
/* rio写入不同类型数据方法。终于调用的是riowrite方法 */
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);
举当中的一个方法实现:
/* Write multi bulk count in the format: "*<count>\r\n". */
/* rio写入不同类型数据方法,调用的是riowrite方法 */
size_t rioWriteBulkCount(rio *r, char prefix, int count) {
char cbuf[128];
int clen; cbuf[0] = prefix;
clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,count);
cbuf[clen++] = '\r';
cbuf[clen++] = '\n';
if (rioWrite(r,cbuf,clen) == 0) return 0;
return clen;
}
调用的还是里面的rioWrite方法,依据你定义的是buffer IO还是File IO,.各自有各自不同的实现而已。
在文件的write方法时,有一个细节,当你把内容读入到rio.file.buffer时。buffer超过给定的同步最小字节,你得必须将buffer内容刷新到文件里了。
/* Returns 1 or 0 for success/failure. */
/* 将buf写入rio中的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; if (r->io.file.autosync &&
r->io.file.buffered >= r->io.file.autosync)
{
//判读是否须要同步
fflush(r->io.file.fp);
aof_fsync(fileno(r->io.file.fp));
r->io.file.buffered = 0;
}
return retval;
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
Redis源代码分析(二十七)--- rio制I/O包裹的更多相关文章
- Redis源代码分析(十七)--- multi事务操作
redis作为一非关系型数据库,居然相同拥有与RDBMS的事务操作,不免让我认为比較吃惊.在redis就专门有文件就是运行事务的相关操作的.也能够让我们领略一下.在Redis的代码中是怎样实现事务操作 ...
- redis 源代码分析(一) 内存管理
一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...
- Redis源代码分析(一)--Redis结构解析
从今天起,本人将会展开对Redis源代码的学习,Redis的代码规模比較小,很适合学习,是一份很不错的学习资料,数了一下大概100个文件左右的样子,用的是C语言写的.希望终于能把他啃完吧,C语言好久不 ...
- Redis源代码分析(十一年)--- memtest内存测试
今天,我们继续redis源代码test下测试在封装中的其它文件.今天读数memtest档,翻译了,那是,memory test 存储器测试工具..可是里面的提及了非常多东西,也给我涨了非常多见识,网上 ...
- Redis源代码分析(23)--- CRC循环冗余算法RAND随机数的算法
他今天就开始学习Redis源代码的一些工具来实现,在任何一种语言工具.算法实现的原理应该是相同的,一些比較经典的算法.比方说我今天看的Crc循环冗余校验算法和rand随机数产生算法. CRC算法全称循 ...
- Android 中View的绘制机制源代码分析 二
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...
- Redis源代码分析(二十八)--- object创建和释放redisObject物
今天的学习更有效率.该Rio分析过,学习之间的另一种方式RedisObject文件,只想说RedisObject有些生成和转换.都是很类似的.列出里面长长的API列表: /* ------------ ...
- Redis源代码分析(二十四)--- tool工具类(2)
在上篇文章中初步的分析了一下,Redis工具类文件里的一些使用方法,包含2个随机算法和循环冗余校验算法,今天,继续学习Redis中的其它的一些辅助工具类的使用方法.包含里面的大小端转换算法,sha算法 ...
- Redis源代码分析(二十二)--- networking网络协议传输
上次我仅仅分析了Redis网络部分的代码一部分,今天我把networking的代码实现部分也学习了一遍,netWorking的代码很多其它偏重的是Clientclient的操作.里面addReply( ...
随机推荐
- 了解ASP.NET5 Web应用程序结构
本文参考ASP.NET5 官方文档 Understanding ASP.NET 5 Web Apps,加入了一些个人理解,理解不对的地方希望大家能指出,互相学习. ASP.NET 5 针对WEB编程引 ...
- UVa11488-Hyper Prefix Sets(trie树)
H Hyper Prefix Sets Prefix goodness of a set string is length of longest common prefix*number of str ...
- 小谷的战斗Jquery(三)--水平和垂直菜单
日薪的例子似乎有点低,今天做多.行,这种实现是一个简单的菜单,Web项目中,有两个共同的菜单:纵向和横向.说到从垂直,看原代码. html代码实现最主要的菜单与子菜单 <span style=& ...
- C#软件开发实例.个人定制自己的屏幕抓图工具(八)加入了截图功能键盘
章文件夹 (一)功能概览 (二)创建项目.注冊热键.显示截图主窗体 (三)托盘图标及菜单的实现 (四)基本截图功能实现 (五)针对拖拽时闪烁卡顿现象的优化 (六)加入配置管理功能 (七)加入放大镜的功 ...
- String、StringBuffer和StringBuilder
一.String和StringBuffer String类型和StringBuffer类型的主要性能差别事实上在于String是不可变的对象,因此在每次对String类型进行改变的时候事实上都等同于生 ...
- 在内存中建立 MySQL 的临时目录(转)
MySQL 系统会在内存(MEMORY)和磁盘(MyISAM)中建立临时表,如何能知道在磁盘中建立了多少临时表以及在内存中建立多少临时表呢?你可以通过下面命令获知: ? 1 2 3 4 5 6 7 m ...
- Effective Java (7) - 避免终止方法
一. 基本概念 1. 所谓的终结方法事实上是指finalize(). 2. Java的垃圾回收机制仅仅负责内存相关清理.其它资源的清理(释放文件.释放DB连接)须要程序猿手动完毕. 3. 调用Syst ...
- innerHTML使用方法
使用方法: 比方在<body>中写了例如以下的代码:<div id=top></div> 如今用top.innerHTML="..........&quo ...
- StackExchange.Redis 使用-发布订阅 (二)
使用Redis的发布订阅功能 redis另一个常见的用途是发布订阅功能 . 它非常的简单 ,当连接失败时 ConnectionMultiplexer 会自动重新进行订阅 . ISubscriber s ...
- HDU 4309 Seikimatsu Occult Tonneru 网络流量+像缩进
主题链接:点击打开链接 意甲冠军: 题意:给出一张N(N<=100)个点,M(M<=1000条)边的有向图. 每一个点上都有一些人.每条边有4个属性(u,v,w,p). 这些边分为三种:( ...