内存缓存是简单的在内存进行读写操作的一种传输,任何时候想在上面写入数据都是放入缓存中,任何时候读操作数据也是来至于缓存。内存缓存的分配使用c语言的malloc类函数,分配的长度是需要长度的两倍,需要考虑这些内存缓存的使用范围。

同样这个类继承至缓存基类TBufferBase,默认的缓存大小是1024(static const uint32_t defaultSize = 1024;),所有的构造函数都调用函数initCommon,这个函数实现如下:

 voidinitCommon(uint8_t* buf, uint32_t size, bool owner, uint32_t wPos) {
if (buf== NULL && size != 0) {//如果传递过来的buf为null并且size不为0
assert(owner);//断言这个内存缓存是不是自己所有,不是就报错不继续执行后面的代码了
buf =(uint8_t*)std::malloc(size);//是自己拥有的内存缓存就自己分配size大小的内存作为缓存
if(buf == NULL) {
throw std::bad_alloc();//分配失败抛出异常
}
}
buffer_= buf;//初始化缓存成员变量
bufferSize_ = size;//大小 rBase_= buffer_;基地址
rBound_= buffer_ + wPos;//界限 wBase_= buffer_ + wPos;//写缓存基地址
wBound_= buffer_ + bufferSize_;//写界限 owner_= owner;//是否自己拥有这段内存缓存
}

上面代码需要说明是:在初始化这个类的时候对于内存缓存是不是属于类自己拥有有不同的处理方式,后面介绍各个方针;还有一点就是读的边界其实就是写的起始地址,因为写入开始的地方就是没有有效数据的地方了,就是一个生存者和消费者的问题,这个后面介绍的一个函数computeRead会更新相关内容。下面我们就看看内存缓存采取的几种可配置的方针(对待内存缓存的方式),是定义一个枚举标识每一个方针的,定义如下:

 enumMemoryPolicy
{ OBSERVE= 1
, COPY =2
,TAKE_OWNERSHIP = 3
};

下面分配分析这三种方针,第一种称为观察方针,意思是内存缓存传输类只是简单的存储一个指针存放到内存,它是调用者来保证内存缓存在剩余的时间指向一个有效的内存,并且在适当的时候清理它(注意:这种内存缓存是不允许写入数据的);第二种是内存缓存类内部的一种拷贝,调用者无任何责任;最后一种就是内存缓存类自己拥有的内存缓存,这个必须自己释放,并且在使用以前需要使用malloc分配。明白了三种内存方针了,就知道什么时候需要的是哪一种。内存使用方针除了被构造函数使用以外,我们在重置内存缓存区时也会使用到,而重置缓存函数是resetBuffer,有两个函数重载。在实现重载函数的时候使用了一点点优化手段,就是交换内存的时候使用std::swap,这个函数的好处就是如果是相同的内存分配器分配的就直接交换指针头就可以了。

同其它缓存类一样,内存缓存类通常采用快读和快写去操作数据,这些操作基类的实现已经满足要求了,只是在缓存中数据不足时就会调用慢读和慢写函数从更底层的传输去拿数据,所以慢写和慢读函数实现是不相同的。我们现在就看看内存缓存类的慢读和慢写函数。慢读函数readSlow函数现实如下:

uint32_t TMemoryBuffer::readSlow(uint8_t* buf,uint32_t len) {
uint8_t*start;//缓存读取开始地址
uint32_tgive;//缓存可以读取的长度
computeRead(len, &start, &give);//计算缓存中可以读取的开始地址和长度 // 把缓存中的数据拷贝到提供的buf中
memcpy(buf, start, give);
returngive;//返回实际读取到的数据,可能小于len
}                                       

在读取数据以前先要计算可以读取的开始地址和长度(因为写函数会更新缓存中的数据),这个功能是函数computeRead实现,代码如下:

voidTMemoryBuffer::computeRead(uint32_t len, uint8_t** out_start, uint32_t*out_give) {
rBound_ = wBase_;//更新读取的边界,写的起始地址就是读取的最大限制地址
//取小者,因为数据可能不够,可利用的读长度就是写的起始地址减去读的起始地址
uint32_t give = std::min(len,available_read());
*out_start = rBase_;//返回的读起始地址
*out_give = give;//返回读取的可用长度
rBase_ += give;//更新读取的起始地址
}

下面继续分析慢写函数的实现,代码如下:

voidTMemoryBuffer::writeSlow(const uint8_t* buf, uint32_t len) {
ensureCanWrite(len);//确保能够写入
// 拷贝数据到写缓存的基地址
memcpy(wBase_, buf, len);
wBase_ += len;//更新写缓存的基地址
}

在写入之前需要保证是可以写入的,实现这个保证的函数是ensureCanWrite,代码如下:

void TMemoryBuffer::ensureCanWrite(uint32_tlen) {
uint32_t avail = available_write();//检查可以利用的缓存空间
if (len <= avail) {//如果空间足够就直接返回了
return;
} if (!owner_) {//检查内存是否自己拥有
throwTTransportException("Insufficient space in external MemoryBuffer");//抛出不是自己拥有不能写入
} // 根据需要增加缓存空间.
uint32_t new_size = bufferSize_;
while (len > avail) {//循环增加,每次都是上次的二倍大小,知道满足要求为止
new_size = new_size > 0 ? new_size * 2 :1;
avail = available_write() + (new_size -bufferSize_);//计算新的可利用空间:新-老+以前可利用
}
void* new_buffer = std::realloc(buffer_,new_size);//重新按照新大小分配缓存空间
if (new_buffer == NULL) {
throw std::bad_alloc();
}
bufferSize_ = new_size;//重置缓存大小 ptrdiff_t offset = (uint8_t*)new_buffer -buffer_;//计算偏移量,下面依次更新缓存值
buffer_ += offset;
rBase_ += offset;
rBound_+= offset;
wBase_ += offset;
wBound_ = buffer_ + bufferSize_;
}

内存缓存类还增加了一些额外的功能:例如按照字符串来读写,方便了对字符串的操作。

thrift之TTransport层的内存缓存传输类TMemoryBuffer的更多相关文章

  1. thrift之TTransport层的分帧传输类TFramedTransport

    帧传输类就是按照一帧的固定大小来传输数据,所有的写操作首先都是在内存中完成的直到调用了flush操作,然后传输节点在flush操作之后将所有数据根据数据的有效载荷写入数据的长度的二进制块发送出去,允许 ...

  2. thrift之TTransport层的缓存传输类TBufferedTransport和缓冲基类TBufferBase

    本节主要介绍缓冲相关的传输类,缓存的作用就是为了提高读写的效率.Thrift在实现缓存传输的时候首先建立一个缓存的基类,然后需要实现缓存功能的类都可以直接从这个基类继承.下面就详细分析这个基类以及一个 ...

  3. thrift之TTransport层的堵塞的套接字I/O传输类TSocket

    本节将介绍第一个实现具体传输功能的类TSocket,这个类是基于TCP socket实现TTransport的接口.下面具体介绍这个类的相关函数功能实现. 1.构造函数 分析一个类的功能首先看它的定义 ...

  4. 3.NetDh框架之缓存操作类和二次开发模式简单设计(附源码和示例代码)

    前言 NetDh框架适用于C/S.B/S的服务端框架,可用于项目开发和学习.目前包含以下四个模块 1.数据库操作层封装Dapper,支持多种数据库类型.多库实例,简单强大: 此部分具体说明可参考博客: ...

  5. thrift之TTransport类体系原理及源码详细解析1-类结构和抽象基类

    本章主要介绍Thrift的传输层功能的实现,传输的方式多种多样,可以采用压缩.分帧等,而这些功能的实现都是相互独立,和上一章介绍的协议类实现方式比较雷同,还是先看看这部分的类关系图,如下: 由上面的类 ...

  6. thrift之默认传输类TTransportDefaults和虚拟传输类TVirtualTransport

    默认传输类TTransportDefaults提供了抽象类TTransport的默认实现,实现了非虚拟的方法(*_virt) read(), readAll(), write(),borrow() a ...

  7. 基于.net的通用内存缓存模型组件

    谈到缓存,我们自然而然就会想到缓存的好处,比如: 降低高并发数据读取的系统压力:静态数据访问.动态数据访问 存储预处理数据,提升系统响应速度和TPS 降低高并发数据写入的系统压力 提升系统可用性,后台 ...

  8. Memcached内存缓存技术

    Memcached是什么,有什么作用? Memcached是一个开源的.高性能的内存缓存软件,从名称上看Mem就是内存的意思,而Cache就是缓存的意思. Memcached通过在事先规划好的内存空间 ...

  9. 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性

    基于.net的分布式系统限流组件   在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...

随机推荐

  1. Linux了解进程的地址空间

    供Linux了解虚拟内存,非常好的引导了.原文链接:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26683523&i ...

  2. Php面向对象 – 继承和重写

    Php面向对象 – 继承和重写 承受: php于,通过类.使用特殊的经营宗旨. 通过定义类,采用extends来表示当前的类对象继承该类的对象. 样例: class C { public  $p_c  ...

  3. 由一道面试题想到的:Finally

    找工作时,有这样一道题: try{}里面有一条return语句,那么紧跟在这个try后的finally{}里的代码会不会执行,什么时候执行,在return之前还是之后? 我没有怎么思考,根据脑子里仅有 ...

  4. jquery插件之DataTables 参数介绍

    DataTables(http://www.datatables.net/)应该是我到目前为止见过的,功能最强大的表格解决方案(当然,不计算其它整套框架中的table控件在内). 先把它主页上写的特性 ...

  5. crawler_Docker_解决用 JavaScript 框架开发的 Web 站点抓取

    [转载,后续补上实践case] 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取 [编者的话]Prerender 服务能够为网络爬虫提供预先渲染的 ...

  6. Call to undefined function mssql_connect()错误解决

    原文:Call to undefined function mssql_connect()错误解决 同事用php+mssql修改一个系统,却一直配置不了环境.遂做了一个测试,一般情况下我们会注意php ...

  7. 多种语言socket编程集锦—win32

    原文 http://www.blogjava.net/huyi2006/articles/263831.html 借此地方整理以下socket编程的多种语言的实现,socket可以跨平台的通信,因此多 ...

  8. 如何把一个c语言程序做成windows服务开机自启动

    原文:如何把一个c语言程序做成windows服务开机自启动 目前写的程序是一个用c语言实现socket侦听的,那么如何把这个程序做成开机自启动呢? 我们是通过vs6.0,编译后生成了.exe文件,然后 ...

  9. lib库实现loadrunner驱动mysql性能测试

    一.添加mysql驱动链接文件到loadrunner的bin和include目录下  以下链接为本人云盘分享,也可百度自行寻找下载源. http://yunpan.cn/cfTxbANSvipGi  ...

  10. win7访问xp共享访问不了

    这个问题不是一天两天了,经历几次了,所以记下来. 1. 一些XP对用户权限作了特殊的优化设置.限制了只有guest用户才能用于做局域网共享用户. 2. 大多数时候,需要设置一个密码,才能用于访问. 3 ...