内存缓存是简单的在内存进行读写操作的一种传输,任何时候想在上面写入数据都是放入缓存中,任何时候读操作数据也是来至于缓存。内存缓存的分配使用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. jQuery表格排序总成-tablesorter

    一个.进口单证 <script type="text/javascript" src="js/jquery.js"></script> ...

  2. Theano学习笔记(三)——图结构

    图结构(Graph Structures)这是理解Theano该基金会的内部运作. Theano编程的核心是用符号占位符把数学关系表示出来. 图结构的组成部分 如图实现了这段代码: importthe ...

  3. 用jQuery写了一个模态框插件

    用jQuery写了一个模态框插件 大家觉得下面的框框好看么, 水印可以去掉(这个任务交给你们了(- o -)~zZ); "info"框 $("div").con ...

  4. Nyoj 吝啬的国度(图论&&双DFS)

    描述在一个吝啬的国度里有N个城市,这N个城市间只有N-1条路把这个N个城市连接起来.现在,Tom在第S号城市,他有张该国地图,他想知道如果自己要去参观第T号城市,必须经过的前一个城市是几号城市(假设你 ...

  5. linux文章(11)---umask和chmod

    一.用途 文将介绍linux环境下有关文件訪问模式相关的命令.         umask用来设置默认的文件訪问模式屏蔽值:chmod用来改动文件的訪问模式.         本文将选取ubuntu1 ...

  6. 1023 Train Problem II(卡特兰数)

    Problem Description As we all know the Train Problem I, the boss of the Ignatius Train Station want ...

  7. axure团队合作开发原型图

    谁是人画或其他原型图的头,但在基本制度的发展时,.我们分配一些人画的原型,其他部分干. 再画一个原型不再是一个人画,一起画,假设大家都各自画自己那一部分.最后再由一个人来整合的画.是非常麻烦. 咱平时 ...

  8. hdu2191 悼念512汶川大地震遇难同胞——珍惜如今,感恩生活

    转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2191 Problem ...

  9. HDU 4873 ZCC Loves Intersection(可能性)

    HDU 4873 ZCC Loves Intersection pid=4873" target="_blank" style="">题目链接 ...

  10. 【百度地图API】让用户选择起点和终点的驾车导航

    原文:[百度地图API]让用户选择起点和终点的驾车导航 摘要: 如果用户搜索“从机场到火车站”,使用驾车导航DrivingRoute会默认显示一条结果.但同一个城市可能有多个机场和火车站,那么,如何用 ...