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的一些使用方式. ...
随机推荐
- CMFCPropertyGridProperty SetValue 出错处理
对CMFCPropertyGridProperty SetValue时容易报错,这种情况一般是Property和value的类型不匹配造成的. 在创建property的时候,指定了数据类型,如果set ...
- include使用中注意的问题
发现include文件不必添加,但是一定要放在工程路径下,不然就找不到,或者也可以在文件上写出完整的路径. 可以修改路径为'include "../src/enc_defines.v&quo ...
- C#窗体技巧
//限制文本框只能输入数字且允许按退格键删除数字,其它键盘输入不予显示private void 文本框名_KeyPress(object sender, KeyPressEventArgs e) { ...
- git 常用操作
查看某文件的某些行的变化历史: $ git log --pretty=short -u -L 2003,2005:Executor.cpp http://stackoverflow.com/quest ...
- ELK日志管理之——logstash配置语法
Logstash 设计了自己的 DSL -- 有点像 Puppet 的 DSL,或许因为都是用 Ruby 语言写的吧 -- 包括有区域,注释,数据类型(布尔值,字符串,数值,数组,哈希),条件判断,字 ...
- C++读写文件ofstream,ifstream,fstream)[转]
在看C++编程思想中,每个练习基本都是使用ofstream,ifstream,fstream,以前粗略知道其用法和含义,在看了几位大牛的博文后,进行整理和总结: 这里主要是讨论fstream的内容:[ ...
- Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试
本文是本人前一段时间做一个简单Java监控工具调研总结,主要包括VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,以及对Java微基准测试的简单介绍, ...
- Android开发学习---sharedpreference的使用
在前面文章中,为了使数据回显,使用的技术思路是,首先,将数据持久化写到ROM或者SDCard中,其中name和password以":"分隔;然后,将数据记取出来,再用split方法 ...
- linux学习之——vim简明教程
摘自 http://blog.csdn.net/niushuai666/article/details/7275406 ——————————正文开始—————————— 你想以最快的速度学习人类史上 ...
- JAVA面向对象初步知识总结:封装、继承、多态
1.封装 把数据和方法包装进类中,以及具体实现的隐藏,常共同被称作是是封装.其结果是一个同时带有特征和行为的数据类型.所谓具体实现的隐藏是通过访问权限控制实现的.JAVA 子类重写继承的方法时,不可以 ...