tail queue代码阅读
tail queue是bdb中用的最多的数据结构. 定义在 src/dbinc/queue.h:
注: TRACEBUF,QMD_TRACE_HEAD等是为了 queue代码的debug, 这里移除出去. 数据结构
======== ```
// type 即为 用户定义的 类型. 比如 db.h,
// struct __db_txn {
// * TAILQ_HEAD(__kids, __db_txn) kids;
// */
// struct __kids { type 即为 _db_txn. 问题: 用什么不直接用 TAILQ_HEAD(__kids, __db_txn) kids?
// struct __db_txn *tqh_first;
// struct __db_txn **tqh_last;
// } kids; #define TAILQ_HEAD(name, type) \ // 理解为 "头结点"
struct name { \
struct type *tqh_first; /* first element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqh_last; /* addr of last next element */ \ // "最后一个元素的tqe_next" 的地址
} #define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \ // 此为具体的元素, 如 __db_txn
struct type **tqe_prev; /* address of previous next element */ \ "前一个元素的tqe_next" 的地址
}
``` 方法定义
========= ```
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first) /**
* 这里做了一个trick. 看TAILQ_HEAD 和TAILQ_ENTRY的定义, 只有 TAILQ_HEAD给了struct name.
* 所以 强制转为 `(struct headname *)`, (而不是 `(struct entryname *)`). 但是 TAILQ_HEAD 和
* TAILQ_ENTRY 的定义是相同的, `(head)->tqh_last)` 为 最后一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 此 `struct entryname` 的地址.
* `(((struct headname *)((head)->tqh_last))->tqh_last)` 即为:
* `(((struct entryname *)((head)->tqh_last))->tqe_prev)`. 倒数第二个元素的 tqe_next.
* TAILQ_PREV 的定义也是这么理解.
*/
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) /**
* field 为type中, queue entry的field. 其 `(elm)->field.tqe_prev)` 为 前一个元素的 tqe_next 的地址,
* 所以如果有 `struct entryname`的话, 即为 前一个元素的 queue entry field 的地址.
* `(((struct headname *)((elm)->field.tqe_prev))->tqh_last)` 即为:
* `(((struct entryname *)((elm)->field.tqe_prev))->tqe_prev)`. 前第二个元素的 tqe_next.
*/
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field)) #define TAILQ_INIT(head) do {
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \ // tqh_last 为 头结点本身的 tqh_first指针的地址
} while () #define TAILQ_CONCAT(head1, head2, field) do { \ // 合并两个queue
if (!TAILQ_EMPTY(head2)) { \ // 若q2 不为空
*(head1)->tqh_last = (head2)->tqh_first;\ // 调整 q1 末尾节点的 tqe_next
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ // 调整q2 第一个节点的tqe_prev
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \ // 重置q2的头结点
} \
} while () #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ // 将elm 插到 listelm 后面
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ // elm->next=listelm->next
TAILQ_NEXT((elm), field)->field.tqe_prev = \ // 若listelm不为队尾, 调整elm->next->pre
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // listelm为队尾, 调整tqh_last
TAILQ_NEXT((listelm), field) = (elm); \ // 调整listelm->next
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ // 调整elm->pre
} while () #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \ // 若listelm为第一个元素, 则tqe_prev为 tqh_first \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \ // queue为空的情况
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ // 第一个元素的 tqe_prev 指向头结点的tqh_first
} while () #define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \ // 若queue为空, tqh_last 指向 tqh_first
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \ // elm 不为队尾, 调整elm->next->pre
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \ // elm 为队尾, 调整tqh_last
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ // 若 elm为队首, 其tqe_prev为 tqh_first
} while ()
```
tail queue代码阅读的更多相关文章
- 代码阅读分析工具Understand 2.0试用
Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...
- Android 上的代码阅读器 CoderBrowserHD 修改支持 go 语言代码
我在Android上的代码阅读器用的是 https://github.com/zerob13/CoderBrowserHD 改造的版本,改造后的版本我放在 https://github.com/ghj ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- [置顶] Linux协议栈代码阅读笔记(一)
Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...
- 图形化代码阅读工具——Scitools Understand
Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java, ...
- Python - 关于代码阅读的一些建议
初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...
- MediaInfo代码阅读
MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...
- Tools - 一些代码阅读的方法
1 初始能力 让阅读思路清晰连贯,保持在程序的流程架构和逻辑实现上,不被语法.编程技巧和业务流程等频繁地阻碍和打断. 语言基础:熟悉基础语法,常用的函数.库.编程技巧等: 了解设计模式.构建工具.代码 ...
- Bleve代码阅读(二)——Index Mapping
引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...
随机推荐
- Ruby-递归和尾递归
递归和迭代的区别 递归: 1)递归就是在过程或函数里面调用自身; 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 迭代: 利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话 ...
- linux组、用户操作相关
Linux删除用户组和用户时常用的一些命令和参数.1.从组中删除用户编辑/etc/group 找到GROUP1那一行,删除 A或者用命令gpasswd -d A GROUP2.建用户:adduser ...
- 试一下CANVAS
// 此应用源代码如下: document.getElementById("codetext").innerHTML = document.getElementById(" ...
- KeepAlived主备模型高可用LVS
部署前准备: 1.至少4台主机:两个Director(HA1,HA2),两个Real Server(RS1,RS2) 2.Director之间时间必须同步,且关闭各主机的防火墙和Selinux 3.出 ...
- C++STL学习笔记_(1)deque双端数组知识
#include<iostream> using namespace std; #include "deque" #include "algorithm&qu ...
- ios UILabel在storyBoard或xib中如何在每行文字不显示完就换行
大家知道怎么用代码让label中的文字换行,只需要 label.numberOfLines = 0; label.text = @"这是第一行啦啦啦啦,\n这是第二行啦啦,\n这是第三行&q ...
- Fedora 21 64位系统安装WPS教程
WPS的Linux版本的出现简直是Linux党的福音,Ubuntu上的WPS安装非常简单,但是在Fedora上却有点小麻烦.主要是库的依赖问题.下面记录一下Fedora 21的64位版安装WPS的完整 ...
- vertical-align 垂直居中
基线:字母‘x’的底部: 中线:与基线的距离为小写字母x高度的一半(即0.5ex),而ex同font-size相关,大部分浏览器认为1ex = 0.5em(em同样也是相对单位,不是绝对单位),因此会 ...
- 【Lua】Lua的几点优化原则
Lua是一门以性能著称的脚本语言,被广泛的应用在很多方面,比如很多游戏的插件. 很多时候,没有必要去考虑性能的问题,不过,如果我们在开始编写代码的时候就以更适当,性能更高的方式与结构去组织代码,对于程 ...
- Asp.Net MVC4入门指南(8):给数据模型添加校验器
在本节中将会给Movie模型添加验证逻辑.并且确保这些验证规则在用户创建或编辑电影时被执行. 保持事情 DRY ASP.NET MVC 的核心设计信条之一是DRY: "不要重复自己(Don’ ...