目录

Block

BlockRef

IOBuf

主要api

tls优化

IOPortal

protobuf接口


首先放上官方介绍:

brpc使用butil::IOBuf作为一些协议中的附件或http body的数据结构,它是一种非连续零拷贝缓冲,在其他项目中得到了验证并有出色的性能。IOBuf的接口和std::string类似,但不相同。

以及官方ppt的这张图

从上到下结构分别为IOBuf,BlockRef和Block。

Block

首先看下Block的结构,block就是一段内存,默认大小为8k,负责数据的实际存储。size表示使用了多少内存,cap为这段内存的容量,数据存储在data,portal_next指向在链表结构下的一块block。

创建一个block的接口为create_block,blockmem_allocate即为malloc,申请到8k内存mem后,在mem上调用placement new,因为block本身也占用了内存,因此实际数据存储data指向mem + sizeof(Block),容量大小为8k-sizeof(Block)。block的写入永远是追加写,不会修改已写入的内容;为了避免全局竞争带来的开销,block引入了tls优化。

block中的nshared字段表示当前block被多少个BlockRef所引用,初始值为1,当block没有被引用时便会被释放。

BlockRef

BlockRef引用了一个block,指向了一个block中的一段区域,开始位置为offset,长度为length。

IOBuf

然后看下IOBuf,IOBuf本质就是管理了多个BlockRef,IOBuf的主要结构为一个BigView和SmallView的联合体

sv表示两个Ref,而bv表示一个ref数组

主要api

然后介绍下IOBuf的主要api。

首先是默认构造函数,默认为sv

append一个IOBuf,不涉及到实际内存的拷贝,只要push下other的ref即可;遍历other所有的ref,然后调用_push_back_ref

如果当前iobuf为sv,那么调用_push_or_move_back_ref_to_smallview,流程如下:

  1. 如果当前iobuf没有ref,那么将sv[0]设置为r,并将r所引用的block进行inc_ref()
  2. 如果当前iobuf的ref[1]为空,那么判断ref[0]和r是否可以合并,如果两个ref引用的block一致,且两段区域连续,那么就将r合并到ref[0]上,否则将sv[1]设置为r
  3. 如果当前iobuf的ref均不为空,那么尝试合并r到ref[1],若无法合并,则将当前iobuf由sv转成bv,为bv申请一定量的ref数组,并将r添加到bv中

_push_or_move_back_ref_to_bigview则判断r是否能与bv的最后一个合并,若不能,则添加到bv最后。

append一个string,此时会涉及内存的拷贝

如果只append一个字符,就会调用push_back()接口,share_tls_block接口是获取到一个未满的block,这个接口后面再说,然后将这个字符加到block中,创建ref并push到当前iobuf中,即完成了append。

如果是append多个字符,那么循环调用share_tls_block得到未满的block,memcpy data到block中,直到拷贝完所有字符。

int IOBuf::appendv(const const_iovec* vec, size_t n)

该接口是将n个iovec的数据append到iobuf,和上述原理差不多。

对于cut类,pop类接口,原理和append也比较相近,不再赘述。

tls优化

然后看下之前提到的tls优化

TLSData就是一个block链表,每个线程有个tls的TLSData,num_blocks表示cache了多少个block,registered表示是否注册了线程退出对tls清理的函数。

然后看下上文提到的share_tls_block

首先是判断当前tls头结点,如果头结点b不是null且未满,那么直接返回b;如果b已经满了,那么将b从tls中移除,dec_ref,并走到b的下一个节点new_block;如果b是null,那么如果没注册线程退出函数就注册下,如果new_block为null,那么通过create_block申请一个block并加入到tls链表中。

而acquire_tls_block接口和share_tls_block类似,区别是acquire会将返回的block移除tls,而share不会移除。

release_tls_block,release_tls_block_chain则是将单个/多个block归还tls

这里申请和归还block并不能保证在同一个thread,可能会出现在A线程申请,在B线程归还的场景。

IOPortal

然后看下IOPortal,IOPortal是IOBuf的子类,可以从fd中读数据,一般用于和socket的交互

append_from_reader和pappend_from_file_descriptor逻辑差不多,区别是前者使用IReader的ReadV,后者使用系统调用readv或者preadv。

do while循环做的事情是不断申请block,直到这些block剩余空间能够存下max_count的数据;并初始化好iovec,iovec初始化为这些block;然后调用readv或者preadv,最后根据block生成blockref。

protobuf接口

最后是基于protobuf的IOBufAsZeroCopyInputStream和IOBufAsZeroCopyOutputStream,继承自google::protobuf::io::ZeroCopyInputStream 和google::protobuf::io::ZeroCopyOutputStream,目的是为了消除用户逻辑同stream交互时发生的拷贝,例如从stream的内存到用户的buf间的拷贝;具体做法为buf的内存不应该由用户逻辑管理,而是由stream来管理;对外暴露两个接口,分别为

bool Next(void** data, int* size),返回一段可写入的连续内存(*data),长度为(*size)

void BackUp(int count),归还不需要使用的内存。

然后解释下next接口:

其实就是申请一个block,然后返回,size为这个block的剩余空间,也因为这样,所以需要acquire来占住整个block。

brpc源码学习(五)-IOBuf相关推荐

  1. brpc源码学习(六)- brpc server 端整体流程

    brpc的使用比较容易上手,以官方demo为例,因为brpc的数据序列化依赖protobuf,所以首先需要定义个proto 然后继承EchoService并实现Echo方法 然后是整体流程 启动还是比 ...

  2. SDN控制器Floodlight源码学习(五)--控制器和交换机交互(3)

    上两篇诣在说明控制器和交换机的交互,但是感觉还是没有理的特别清楚 http://blog.csdn.net/crystonesc/article/details/70143117 http://blo ...

  3. brpc源码学习(二)-bthread的创建与切换

    brpc引入m:n的线程模型,固定的内核线程调度运行大量的bthread以避免内核线程上下文切换带来的开销. bthread类似协程,即用户态线程,bthread的切换不会陷入内核,不会进行一系列内存 ...

  4. brpc源码学习(一)-butex

    由于brpc中引入了bthread,如果在bthread中使用了mutex,那么将会挂起当前pthread,导致该bthread_worker无法执行其他bthread,因此类似pthread和fut ...

  5. lua_gc 源码学习五

    今天来说说 write barrier . 在 GC 的扫描过程中,由于分步执行,难免会出现少描了一半时,那些已经被置黑的对象又被修改,需要重新标记的情况.这就需要在改写对象时,建立 write ba ...

  6. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

  7. action mutation 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    module与moduleCollection你一定要会啊!Vuex源码学习(五)加工后的module 在组件中使用vuex的dispatch和commit的时候,我们只要把action.mutati ...

  8. Vuex 4源码学习笔记 - 通过dispatch一步步来掌握Vuex整个数据流(五)

    在上一篇笔记中:Vuex 4源码学习笔记 - Store 构造函数都干了什么(四) 我们通过查看Store 构造函数的源代码可以看到主要做了三件事情: 初始化一些内部变量以外 执行installMod ...

  9. Vuex源码学习(五)加工后的module

    没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection 感谢提出代码块和截图建议的小伙伴 代码块和截图的区别: 代码块部分希望大家按照我 ...

最新文章

  1. 认清Hadoop和Spark的这几点区别,学习时才能事半功倍
  2. 单片机值得学吗?会单片机能找什么工作?
  3. SAP RETAIL 通过自动补货功能触发采购申请
  4. spark sql 上个月_SPARK-SQL内置函数之时间日期类
  5. Session与Cookie区别[1][摘]
  6. Leetcode 82. 删除排序链表中的重复元素 II (每日一题 20210908)
  7. .Net Core开发日志——Peachpie
  8. [SpringBoot2]web场景_静态资源规则与定制化
  9. CSS+jQuery实现滑动幻灯片实例详解
  10. linux cpu intr s,mpstat命令(linux cpu监控工具)
  11. oracle双机python连接_Python 连接 Oracle 示例
  12. java 置顶窗体_windows 下如何让一个窗口置顶?
  13. 数据库课设之学生信息管理系统
  14. 思岚A2 运行cartographer
  15. 鸿蒙系统视频美颜,BeautyCam美颜相机
  16. Photoshop教程:10秒闪电搞定照片构图
  17. LSTM的优点和缺点
  18. iGrimaceV8 V8在线威锋源apt.so/tuzhurenv8手机直接下载安装教程图:
  19. Linux必会100个命令(三十八)halt
  20. 关于浏览器加载不出图片的问题

热门文章

  1. 从零深入理解Yolo系列理论v1-v8 + 目标检测面试提问
  2. 二见钟情之SQL语句嵌套查询
  3. lol人数最多的服务器,谁说“黑色玫瑰”妹子最多?LOL国服各大服务器趣闻盘点...
  4. JAVA 知识点 | Hook
  5. 简单便宜智能家居解决方案
  6. 觉得tkinter界面不好看?Extkinter带你制作进阶版窗口(ExButton篇)
  7. Java的String类的常用方法【总结】
  8. 鸿蒙系统会用于所有华为手机吗,第二款鸿蒙终端发布!搭载鸿蒙系统的华为手机还会远吗?...
  9. RedisTemplate指令
  10. 专业放心的python入门视频_手把手教你掌握学习Python方法,让你不再从入门到放弃...