brpc组件bvar源码解析(三)Variable、Reducer和Adder

2023-11-11

1.Variable类

Variable是所有bvar的基类,是一个纯虚类。拥有的唯一的成员变量是_name。

Variable类中的接口分为几类:

  1. 描述相关的
    在这里插入图片描述
    子类实现纯虚函数describe,目的是将bvar的值写入ostream。

get_description不是纯虚函数,它调用了describe写入ostringstream,返回ostringstream的string。

  1. 曝光相关的
    例如:expose,expose_impl,expose_as,list_exposed,count_exposed,describe_exposed,dump_exposed等。核心是expose_impl,下文介绍。

函数expose_impl

在这里插入图片描述
函数expose_impl是实现曝光的核心逻辑。所谓“曝光”就是把bvar的地址存到一个公共的map中,以便后续可以遍历和查询到。

具体的做法是:
(1)根据prefix+name生成统一格式的曝光名称_name:非字母、非数字的全部转成下划线
(2)根据(1)生成的曝光名称_name查询所属的VarMapWithLock:
首先对_name进行了简单的hash,然后对VarMapWithLock数组s_var_maps的长度SUB_MAP_COUNT取模得到i,返回s_var_maps的第i个成员。这里这么做的目的是为了减少VarMapWithLock中的锁竞争的频率。
在这里插入图片描述

(3)根据_name查询VarMapWithLock中是否存在key为_name的记录
VarMapWithLock其实就是加了锁的hashmap。
在这里插入图片描述

如果查不到,则插入pair<name, VarEntry>,VarEntry的var变量赋值this值,display_filter变量赋值入参display_filter。
在这里插入图片描述
display_filter是枚举类型DisplayFilter,表示显示到文本中、html中还是全部。list_exposed函数会将入参和所有VarEntry的display_filter进行与操作,只输出满足条件的bvar。
在这里插入图片描述

(4)如果(3)能查到记录,说明有同名bar已经进行了曝光,则根据gflags进行相关处理(直接abort或者打印error log)

函数hide

在这里插入图片描述
很容易理解,就是根据_name从对应的VarMapWithLock中删除记录。

函数list_exposed

在这里插入图片描述
在这里插入图片描述

遍历所有曝光的bvar,即遍历s_var_maps中的所有map的所有pair,选出满足display_filter条件的bvar的name保存到names数组中。

遍历s_var_maps中的每个map时,首先都需要先加锁,才能遍历map中的每个pair。为了防止个数太多、加锁时间过长,遍历每超过一定个数(256个),都主动释放一下锁。

函数describe_exposed

在这里插入图片描述
即根据name从s_var_maps查询到VarEntry*,调用该bvar的describe函数,结果保存到os中。

函数dump_exposed

在这里插入图片描述
查询所有曝光的bvar,将符合options中的通配符white_wildcards和black_wildcards条件的bvar都调用dumper->dump函数。例如white_wildcards = “foo_bar_*”; black_wildcards = “*var5”。函数返回值是dump的bvar的个数。

如果通配符white_wildcards是空的,那么先通过list_exposed得到所有曝光的bvar的name,然后对name进行排序,遍历name数组,对于符合通配符条件的name,调用describe_exposed函数将该bvar的描述保存到ostream,然后调用dumper->dump函数,传入name和保存描述的ostream转成的字符串。

Dumper是一个纯虚类,由开发者自己继承实现。
在这里插入图片描述

2.Reducer类

Reducer类定义:
在这里插入图片描述
3个模板类型:
T:bvar保存的值的类型
Op:“累加”的op
InvOp:与“累加”相反操作的OP,默认是VoidOp即无具体操作;这个介绍采样的时候再具体介绍。

成员变量:
在这里插入图片描述
构造函数:
在这里插入图片描述
add_cr_non_integral是如果T不是整型则增加const&修饰。
identity赋值T的默认构造函数生成的对象,如果T是POD类型,则T()就是0值。

_combiner:AgentCombiner<T, T, Op>类的对象;AgentCombiner的第1、第2模板参数都是T,说明它的结果类型和元素类型是相同的、都是T(介绍AgentCombiner时说过这2个类型可以不同)
_sampler:ReducerSampler<Reducer, T, Op, InvOp>类型的指针,此处设置为NULL,只有当前bvar有采样需要,即成员函数get_sampler被调用时_sampler才会被new出来。
_series_sampler:嵌套类SeriesSampler类型的指针,此处设置为NULL,后面介绍采样时再介绍。
_inv_op:InvOp类的对象。

Op类的对象在_combiner中有保存,所以不需要重复保存;

函数operator<<

在这里插入图片描述
函数operator<<是对bvar增加值时调用的,例如

bvar::Adder<int> sum;
sum << 1 << 2 << 3 << 4;
LOG(INFO) << sum.get_value(); // 10

具体实现是:
(1)调用_combiner的get_or_create_tls_agent函数,获得此bvar在当前线程tls数据中存储的agent的地址;
(2)然后调用agent->element.modify,传入Op对象和入参value,内部通过call_op_returning_void调用Op对象的函数operator()实现element当前值与入参value的“累加”、并将新值保存到agent->element。
在这里插入图片描述
(3)返回当前对象的引用,以便实现连续操作;
(4)这个函数调用栈完全没有锁,所以即使bvar在不同线程调用性能也很高。

函数get_value

在这里插入图片描述
这个函数目的是获得bvar的最新值,那么就要把在各个线程tls存储的agent的值进行“累加”。
实现上由于_combiner.combine_agents已经封装好了这个功能,所以直接调用并返回即可。

_combiner.combine_agents调用栈底部有加锁操作,所以应该尽量少调用。

函数describe

在这里插入图片描述
调用get_value获得最新值保存到os中,如果T为string类型并且quote_string为true,则前后加上引号。

函数expose_impl

在这里插入图片描述

这里override了基类虚函数Variable::expose_impl。主要是调用了Variable::expose_impl进行了实际的曝光操作,然后根据条件和参数初始化了_series_sampler(这个后面介绍采样时再介绍)。

3.Adder类

在这里插入图片描述
在这里插入图片描述
由于父类Reducer该实现的都实现了,所以Adder定义就比较简洁了。重点就是传3个模板参数,一个是值类型T,一个是“累加”Op:AddTo类,一个是“逆反”Op:MinusFrom类。

Op有一个注意点是:必须把新值保存到第一个参数lhs中,而不是返回。

(待续)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

brpc组件bvar源码解析(三)Variable、Reducer和Adder 的相关文章

随机推荐

  • 练习-Java继承和多态之接口

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 题目 任务 编写一个学校接待方面的程序 招待不同身份的人的食宿问题 编程要求 仔细阅读右侧编辑区内给出的代码框架及注释 在 Begin End 中编写一个学校接待方面的程序
  • 什么是电力系统的功率平衡?为什么在任何时候要保持电力系统的功率平衡?

    什么是电力系统的功率平衡 为什么在任何时候要保持电力系统的功率平衡 答 电力系统的功率平衡是指电力有功功率和无功功率的平衡 这种功率平衡也就是电力供需平衡 要求电力系统发送的功率与系统的负荷需要随时保持平衡 电能的一个最重要特点就是不能储存
  • 关于Vue.js中数据模型的绑定以及方法事件的绑定与调用

    在vue js中 我们可以将事件方法写在methods属性中 数据模型在data中定义 Vue的基本结构如下 只写最常用的 将数据与vue实例绑定通过v bind标签 这里绑定的是sourceId这个值 基于vue的双向绑定 如果要取vue
  • 蓝桥杯:整除序列

    整除序列 15分 题目描述 有一个序列 序列的第一个数是 n 后面的每个数是前一个数整除 2 请输出这个序列中值为正数的项 输入格式 输入一行包含一个整数 n 输出格式 输出一行 包含多个整数 相邻的整数之间用一个空格分隔 表示答案 评测用
  • 虚拟环境安装和操作

    文章目录 安装相应库和配置 查看已安装虚拟环境 创建虚拟环境 切换 进入虚拟环境 退出虚拟环境 虚拟环境 linux创建Python虚拟环境及配置 Django Flask项目中如何创建Python虚拟环境呢 汇总 环境迁移 安装相应库和配
  • 攻防世界MISC刷题1-50

    目录 1 ext3 2 base64stego 3 功夫再高也怕菜刀 4 easycap 5 reverseMe 6 Hear with your Eyes 7 What is this 8 normal png 9 something i
  • idea 添加 VUE 的语法支持和开发

    一 VUE的开发分两种 一种是直接在HTML文件中使用 一种是VUE文件的形式开发 1 首先我们先让 HTML 文件支持 VUE 的语法指令提示 2 File gt Setting gt Edit gt Inspections gt htm
  • 父类A a = new 子类B

    父类名 a new 子类名 子类名 b new 子类名 比较上面两种创建实例的区别 a只能调用父类的函数 和子类重写父类的方法 不能调用父类中不存在的子类的函数 因为它没有继承 a是父类的引用 指向了一个子类对象 好处如果一旦发现该B对象无
  • Jetson Orin NX install Fastdeploy

    FastDeploy jetson md at develop PaddlePaddle FastDeploy GitHub sudo apt get install gcc sudo apt get install cmake git c
  • postman-token的作用

    Postman生成的代码中的postman token是什么 What is the postman token in generated code from Postman 这主要用于绕过Chrome 等其他浏览器 中的错误 如果XMLH
  • QEMU/KVM PCI Passthrough(i350) & DPDK 网络性能测试

    QEMU KVM PCI Passthrough i350 DPDK 网络性能测试 硬件要求 CPU必须支持硬件虚拟化 Intel VT d or AMD Vi 和 IOMMU 原图链接 主机配置 设置iommu IOMMU kernel
  • kmp算法(最简单最直观的理解,看完包会)

    本文将以特殊的方式来让人们更好地理解kmp算法 不包括kmp算法的推导 接下来 我们将从朴素算法出发 在这之前 我们先设主串为S 模式串为T 我们要解决的询问是主串中是否包含模式串 即T是否为S的子串 版权声明 本文为原创文章 转载请标明出
  • c++ 继承 学习总结1 继承的基本语法

    前言 继承的作用是减少程序中重复的代码段 如果程序中有很多重复的代码段 可以考虑一下能否使用继承 继承的语法 class 子类 继承方式 父类 include
  • 特征提取-特征工程

    目录 1 定义 2 字典特征提取 3 英文 本特征提取 4 中文 本特征提取 1 定义 将任意数据 如 本或图像 转换为可 于机器学习的数字特征 2 字典特征提取 from sklearn feature extraction import
  • 【算法】树状数组维护总结

    本文仅对树状数组的使用作一个总结 并非讲解 这里的操作都对长度为 n n n 的数组 a a a 进行操作 单点修改 区间查询 暴力做法 修改
  • java使用原始套接字技术进行数据包截获_Linux零拷贝技术,看完这篇文章就懂了...

    本文讲解 Linux 的零拷贝技术 云计算是一门很庞大的技术学科 融合了很多技术 Linux 算是比较基础的技术 所以 学好 Linux 对于云计算的学习会有比较大的帮助 本文借鉴并总结了几种比较常见的 Linux 下的零拷贝技术 相关的引
  • python的pyecharts绘制各种图表详细(代码)

    环境 pyecharts库 echarts countries pypkg echarts china provinces pypkg echarts china cities pypkg 数据 2018年4月16号的全国各地最高最低和天气
  • 5.5js

    1 JavaScript简介 什么是JavaScript JavaScript 是 种客户端脚本语 脚本语 是 种轻量级的编程语 JavaScript 通常被直接嵌 HTML 由浏览器解释执 JavaScript 是 种解释性语 就是说 代
  • Deepin 手动分区记录

    起初安装Deepin 采用手动分区 总是安装失败 经过以下分区就成功安装了 efi 分区 默认300m boot 分区 默认 512m 交换分区 swap 等于你的内存大小 分区 15G home 分区剩余全部容量 home可以设置也可以不
  • brpc组件bvar源码解析(三)Variable、Reducer和Adder

    1 Variable类 Variable是所有bvar的基类 是一个纯虚类 拥有的唯一的成员变量是 name Variable类中的接口分为几类 描述相关的 子类实现纯虚函数describe 目的是将bvar的值写入ostream get