这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题。

引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论:

struct {
int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小
int total_nr_elements; // 这是全部flex_array_part结构体中的哈希头指针的总个数
int elems_per_part; // 这是每一个part指针指向的空间能存储多少个哈希头指针
u32 reciprocal_elems;
struct flex_array_part *parts[]; // 结构体指针数组。里面存放的是struct flex_array_part结构的指针
};

事实上这个结论是正确的,这些结构体成员的含义就是这些意思。但前篇分析中这个结论和static inline int elements_fit_in_base(struct flex_array *fa)函数产生矛盾。这里也看下该函数的详细实现:

static inline int elements_fit_in_base(struct flex_array *fa)
{
// fa->element_size 依据上面的结论应该是哈希头的大小,flex_array_part结构体中存放的哈希头大小
// fa->total_nr_elements 依据上面的结论应该是全部哈希头的总数
// 那么data_size 就是全部存储哈希头的空间大小了,矛盾来了
int data_size = fa->element_size * fa->total_nr_elements;
// FLEX_ARRAY_BASE_BYTES_LEFT是什么意思呢?
// #define FLEX_ARRAY_BASE_BYTES_LEFT (FLEX_ARRAY_BASE_SIZE - offsetof(struct flex_array, parts))
// offsetof()宏用来求一个成员在结构体中的偏移量
// 所以全部存储哈希头空间的大小和 FLEX_ARRAY_BASE_BYTES_LEFT 比較是什么意思呢?
// 我当时的推断就是element_size和total_nr_elements这两个成员变量理解错了。 if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT)
return 1;
return 0;
}

假设依照一般的思想来分析这个源码真的有问题了,至少这个函数分析不下了。那么真正的原因是什么呢?

首先来看下哈希桶内存申请函数(在上篇中有分析)当中传过来的分别为:elements = sizeof(struct hlist*)和total = 1024(宏定义而来)。

再看看上面这个函数的实现:data_size = element_size * total_nr_elements; 也即是 data_size = elements * total;带入数据得:data_size = 4 * 1024 = 4096(由于两个參数一个是宏定义的。对整个项目来说是不变的;另外一个也一样是不会变的。所以能够当做常量带入去应验下);

那么如今来看看if推断语句:data_size <= (4096 - 4*4)。由于依据上面的flex_array结构体成员变量能够知道:有3个int型成员和一个u32类型的成员。

所以得到parts前有 4*4个字节。用一个页的大小减去到parts成员前的字节为:4096 - 4*4。

最后把全部数据带入能够得到:4096 <= (4096 - 4*4);那么这个条件肯定是恒不成立的。所以这个函数就是多余的了,由于data_size的值是一定为4096的。无论flex_array结构中成员变量代表什么意思。而FLEX_ARRAY_BASE_BYTES_LEFT也是一定不变的。

得到上面的结论事实上离真相就比較接近了,能够想象得到一个由这么多顶尖的程序猿设计出来的项目,不太可能会出现一个冗余的函数。并且在flex_array.c中大量的使用。那么这个函数一定有其它用处,我想了非常多种可能,也重复的分析flex_array.c和flex_array.h中的源码,最后我得到一种猜想:就是当这个项目中所要的最大元素数非常小。就是说依据需求total不须要1024。不要那么大呢?

猜想:须要的流表项链表头结点比較少(total_nr_elements < 1024)。那么不须要分配一个parts指针(一个parts数组指针元素有一个页大小的空间)来存储。假设total_nr_elements不大于1020,就不是必需分配parts指针了。直接在flex_array结构体(该结构体的大小为一个页,有3个int型和1个u32成员,所以剩下的就是1020 * 4个字节了)中存储就得了。

以下来验证下这个猜想,来分析调用了static inline int elements_fit_in_base(struct flex_array *fa)函数的各个代码:

if (elements_fit_in_base(fa))
part = (struct flex_array_part *)&fa->parts[0];
else {
part_nr = fa_element_to_part_nr(fa, element_nr);
part = __fa_get_part(fa, part_nr, flags);
if (!part)
return -ENOMEM;
}

这段代码在非常多函数中都有。能够看int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,gfp_t flags);数据拷贝函数的详细实现。该代码中调用了elements_fit_in_base(fa)来推断,假设成立。也就是说total_nr_elements不大于1020;那么直接用数组头元素的地址来强转为须要的结构体。即是直接在数组头元素存储的地方開始操作,而不是数组头元素指向的地方開始操作。说明了数据就是存储在flex_array结构体中。

以下来看另外一段代码:

void flex_array_free_parts(struct flex_array *fa)
{
int part_nr; if (elements_fit_in_base(fa))
return;
for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
kfree(fa->parts[part_nr]);
}

看这段代码大概就知道是用来释放parts内存的。该代码中调用了elements_fit_in_base(fa),假设成立。也就是说total_nr_elements不大于1020;那么就直接返回,什么都不运行。

这就暗示了这个项目中根本就没有申请parts内存,全部的流表项链表头结点都是存放在flex_array结构体中的。

再看下行的for循环,是从0開始的,更能说明假设total_nr_elements大于1020就一定得申请parts内存。

还有其它代码中调用了该函数,就不一一列证了。

就眼下为止来说这个猜想还是比較符合源码的。我不能百分百的说这个猜想是正确的。希望有兴趣的朋友能够分析下。

当然我也在找各种途径去分析这个矛盾和猜想。

        转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/39939241
        分析得比較匆促,若有不对之处,望大家指正,共同学习!

谢谢。!

openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)的更多相关文章

  1. nodejs的Express框架源码分析、工作流程分析

    nodejs的Express框架源码分析.工作流程分析 1.Express的编写流程 2.Express关键api的使用及其作用分析 app.use(middleware); connect pack ...

  2. 鸿蒙内核源码分析(双向链表篇) | 谁是内核最重要结构体? | 开篇致敬鸿蒙内核开发者 | v1.11

    子曰:"见贤思齐焉,见不贤而内自省也."<论语>:里仁篇 百篇博客系列篇.本篇为: v01.xx 鸿蒙内核源码分析(双向链表篇) | 谁是内核最重要结构体 | 51.c ...

  3. openVswitch(OVS)源代码分析之工作流程(数据包处理)

    上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到 ...

  4. openVswitch(OVS)源代码分析之工作流程(flow流表查询)

    原文链接: openVswitch(OVS)源代码分析之工作流程(flow流表查询)

  5. 安卓MonkeyRunner源码分析之工作原理架构图及系列集合

    花了点时间整理了下MonkeyRunner的工作原理图,请配合本人博客里面MonkeyRunner其他源码分析文章进行阅读.下面整理成相应系列列表方便大家阅读: MonkeyRunner源码分析之-谁 ...

  6. [Abp vNext 源码分析] - 4. 工作单元

    一.简要说明 统一工作单元是一个比较重要的基础设施组件,它负责管理整个业务流程当中涉及到的数据库事务,一旦某个环节出现异常自动进行回滚处理. 在 ABP vNext 框架当中,工作单元被独立出来作为一 ...

  7. Okhttp源码分析--基本使用流程分析

    Okhttp源码分析--基本使用流程分析 一. 使用 同步请求 OkHttpClient okHttpClient=new OkHttpClient(); Request request=new Re ...

  8. 安卓Monkey源码分析之运行流程

    在<MonkeyRunner源码分析之与Android设备通讯方式>中,我们谈及到MonkeyRunner控制目标android设备有多种方法,其中之一就是在目标机器启动一个monkey服 ...

  9. SpringMVC源码分析-400异常处理流程及解决方法

    本文涉及SpringMVC异常处理体系源码分析,SpringMVC异常处理相关类的设计模式,实际工作中异常处理的实践. 问题场景 假设我们的SpringMVC应用中有如下控制器: 代码示例-1 @Re ...

随机推荐

  1. css 遮照镂空效果

    实现这个效果有以下几种方式.(欢迎指出不足之处!!!)  一:最简单最粗暴的方法!截图! 实现原理:先截一张图片,然后写一个遮罩层,再把图片放上去就可以了! 过程过于简单,就别写代码跟截图效果了! 优 ...

  2. [NOIP2012提高组]疫情控制

    题目:洛谷P1084.codevs1218.Vijos P1783. 题目大意:有一棵n个节点的,根为1的带权树和m支军队.每支军队可以在一个点上停下,那么从1开始就不能经过这个点了.现在有m支军队已 ...

  3. makefile--回顾基础篇

    前阵子让写makefile,纠结了下,基本忘记差不多了. 1.gcc的编译选项 -c 只是编译不链接,生成目标文件“.o” -S 只是编译不汇编,生成汇编代码 -E 只进行预编译,不做其他处理 -g ...

  4. 解决Vue引入百度地图JSSDK:BMap is undefined 问题

    百度地图官网文档介绍使用JSSDK时,仅提供了2种引入方式: script引入 异步加载 解决跨域问题,实例调用百度地图 但vue项目中仅某一两个页面需要用到百度地图,所以不想在 index.html ...

  5. 洛谷 P1052 过河 (离散化+dp)

    dp非常好想, f[i] = min(f[i-len] + stone[i]) s <= len <= t 然后因为L非常大,所以我就不知道该怎么搞了 我看到m只有100,而L有1e9,我 ...

  6. OpenJudge 1031 Lausanne Capitale Olympique

    Lausanne Capitale Olympique Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on  ...

  7. XML快速注释

    eclipse中编辑java或C/C++,python文件时,注释的快捷键均为 "CTRL + / ",编辑xml文件时,该快捷键无效. eclipse XML 注释:CTRL + ...

  8. 洛谷 P1702 突击考试

    P1702 突击考试 题目描述 一日,老师决定进行一次突击考试.已知每个学生都有一个考试能力等级,教室里一共有N个课桌,按照顺序排成一列,每张课桌可以坐两个人,第i张课桌坐的两个人的能力等级为(A[i ...

  9. HP-lefthand底层结构具体解释及存储灾难数据恢复

    HP-lefthand底层结构具体解释及存储灾难数据恢复 一.HP-lefthand的特点 HP-lefhand是一款很不错的SAN存储,使用iscsi协议为client分配空间. 它支持RAID5. ...

  10. AvtiveMQ 参考

    推荐学习:https://www.cnblogs.com/zhuxiaojie/p/5564187.html#autoid-2-1-0