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代码阅读的更多相关文章

  1. 代码阅读分析工具Understand 2.0试用

    Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...

  2. Android 上的代码阅读器 CoderBrowserHD 修改支持 go 语言代码

    我在Android上的代码阅读器用的是 https://github.com/zerob13/CoderBrowserHD 改造的版本,改造后的版本我放在 https://github.com/ghj ...

  3. Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  4. [置顶] Linux协议栈代码阅读笔记(一)

    Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...

  5. 图形化代码阅读工具——Scitools Understand

    Scitools出品的Understand 2.0.用了很多年了,比Source Insight强大很多.以前的名字叫Understand for C/C++,Understand for Java, ...

  6. Python - 关于代码阅读的一些建议

    初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...

  7. MediaInfo代码阅读

      MediaInfo是一个用来分析媒体文件的开源工具. 支持的文件非常全面,基本上支持所有的媒体文件. 最近是在做HEVC开发,所以比较关注MediaInfo中关于HEVC的分析与处理. 从Meid ...

  8. Tools - 一些代码阅读的方法

    1 初始能力 让阅读思路清晰连贯,保持在程序的流程架构和逻辑实现上,不被语法.编程技巧和业务流程等频繁地阻碍和打断. 语言基础:熟悉基础语法,常用的函数.库.编程技巧等: 了解设计模式.构建工具.代码 ...

  9. Bleve代码阅读(二)——Index Mapping

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

随机推荐

  1. svn命令

    1.检出.更新.提交 svn chectout http://svn_server/xxx_repository/trunk svn update svn commit -m "XXX&qu ...

  2. hashchange事件的认识

    写过路由的同学都知道其原理是通过URL的改变,由导航信息来决定页面信息...表述的好像有点不准确 这么说吧,只要URL参数列表只要变化就会调用hashchange事件,此时event对象包括oldUR ...

  3. img

    public BitmapImage BitmapToImage(System.Drawing.Bitmap bitmap) { System.Drawing.Bitmap bitmapSource ...

  4. redis——持久化篇

    众所周知,redis是内存数据库,它把数据存储在内存中,这样在加快读取速度的同时也对数据安全性产生了新的问题,即当redis所在服务器发生宕机后,redis数据库里的所有数据将会全部丢失. 为了解决这 ...

  5. sap MD04中常用函数

    1. 需求溯源 : MD_PEGGING_NODIALOG 2. 实时库存 : MD_STOCK_REQUIREMENTS_LIST_API 这个函数中MDPSX 和 MDEZX 是通过 MDPS 的 ...

  6. Android环境配置及运行helloWord案例

      Android的环境搭建步骤,以及输出一个helloWorder 1:下载Android开发环境   及是: SDK adt-bundle-windows-x86_64-20140702 此时的版 ...

  7. mysql学习(1)-linux操作系统源码包安装

    背景: CentOS 6.4下通过yum安装的MySQL是5.1版的,比较老,所以就想通过源代码安装高版本的5.6.22. 正文: 一:卸载旧版本 使用下面的命令检查是否安装有MySQL Server ...

  8. js汉语转拼音(全拼、首字母、拼音首字母)

    新建js文件first_alphabet.js // JavaScript Document // 汉字拼音首字母列表 本列表包含了20902个汉字,用于配合 ToChineseSpell //函数使 ...

  9. Xamarin踩坑经历

    1.SDK版本 Android SDK Build-tools必须安装23.0.1版,不得升级高版本,否则将导致异常:尝试在条件"$(_DeviceSdkVersion) >= 21& ...

  10. Flask+Nginx+uWSGI在Ubuntu服务器上的配置

    Flask+Nginx+uWSGI在Ubuntu服务器上的配置 Step1 安装系统环境 Ubuntu服务器选择是阿里云的ECS服务,ECS提供单独的内存\CPU\带宽\存储规格可以选择,并且提供合适 ...