天天看点

《Ceph源码分析》——第2章,第2节Buffer

本节书摘来自华章出版社《ceph源码分析》一书中的第2章,第2.2节buffer,作者常涛,更多章节内容可以访问云栖社区“华章计算机”公众号查看

2.2 buffer

buffer就是一个命名空间,在这个命名空间下定义了buffer相关的数据结构, 这些数据结构在ceph的源代码中广泛使用。下面介绍的buffer::raw类是基础类,其子类完成了buffer数据空间的分配,buffer::ptr类实现了buffer内部的一段数据,buffer::list封装了多个数据段。

2.2.1 buffer::raw

类buffer::raw是一个原始的数据buffer,在其基础之上添加了长度、引用计数和额外的crc校验信息,结构如下:

`class buffer::raw {

public:

……

}

下列类都继承了buffer::raw,实现了data对应内存空间的申请:

类raw_malloc实现了用malloc函数分配内存空间的功能。

类class buffer::raw_mmap_pages实现了通过mmap来把内存匿名映射到进程的地址空间。

类class buffer::raw_posix_aligned调用了函数posix_memalign来申请内存地址对齐的内存空间。

类class buffer::raw_hack_aligned是在系统不支持内存对齐申请的情况下自己实现了内存地址的对齐。

类class buffer::raw_pipe实现了pipe做为buffer的内存空间。

类class buffer::raw_char使用了c++的new操作符来申请内存空间。

2.2.2 buffer::ptr

类buffer::ptr就是对于buffer::raw的一个部分数据段。结构如下:

`class ceph_buffer_api ptr {

raw *_raw;

unsigned _off, _len;

}`

ptr是raw里的一个任意的数据段,_off是在_raw里的偏移量,_len是ptr的长度。raw和ptr的示意图如图2-1所示。

图2-1 raw和ptr示意图

《Ceph源码分析》——第2章,第2节Buffer

2.2.3 buffer::list

类buffer::list是一个使用广泛的类,它是多个buffer::ptr的列表,也就是多个内存数据段的列表。结构如下:

`class ceph_buffer_api list {

std::list _buffers; //所有的ptr

unsigned _len; //所有的ptr的数据总长度

unsigned _memcopy_count; //当调用函数rebuild用来内存对齐时,需要内存拷贝的数据量

ptr append_buffer; //当有小的数据就添加到这个buffer里

mutable iterator last_p; //访问list的迭代器

buffer::list的重要的操作如下所示。

添加一个ptr到list的头部:

`void push_front(ptr& bp) {

if (bp.length() == 0)

_buffers.push_front(bp);

_len += bp.length();

添加一个raw到list头部中,先构造一个ptr,后添加list中:

`void push_front(raw *r) {

ptr bp(r);

push_front(bp);

判断内存是否以参数align对齐,每一个ptr都必须以align对齐:

`bool buffer::list::is_aligned(unsigned align) const

{

for (std::list::const_iterator it = _buffers.begin();

添加一个字符到list中,先查看append_buffer是否有足够的空间,如果没有,就新申请一个4kb大小的空间:

``void buffer::list::append(char c)

// 检查当前的append_buffer是否有足够的空间

unsigned gap = append_buffer.unused_tail_length();

if (!gap) {

append_buffer = create_aligned(ceph_buffer_append_size,

}``

内存对齐:有些情况下,需要内存地址对齐,例如当以directio方式写入数据至磁盘时,需要内存地址按内存页面大小(page)对齐,也即buffer::list的内存地址都需按page对齐。函数rebuild用来完成对齐的功能。其实现的方法也比较简单,检查没有对齐的ptr,申请一块新对齐的内存,把数据拷贝过去,释放内存空间就可以了。

buffer::list还集成了其他额外的一些功能:

把数据写入文件或从文件读取数据的功能。

计算数据的crc32校验。