源码在Ut0lst.h中
注意:这里我将链表中的实际的串联的数据叫做数据类比如:lock_t、mem_block_t
链表作为一种的非常重要的数据结构,在任何地方都会用到,这里简单解释一下innodb双向链表的实现,让我们来看看innodb链表设计的魅力:
经常在某些结构体中看到
UT_LIST_BASE_NODE_T(mem_block_t) base;
UT_LIST_NODE_T(mem_block_t) list;
作为最为基本的一种的数据结构innodb中实现得比较精妙涉及到重要的4个C++知识点:
1、仿函数
2、类成员指针
3、类模板
4、函数重载
简单的说仿函数是调用的时候类似函数调用的形式的类,类成员指针并非一个真正意义上的指针,而是指向特定类对象相对位置的一个偏移量。
比如如下就是一个仿函数类:
template <typename T>
class ShowElemt
{
public:
ShowElemt()
{
n = 0;
}
void operator()(T &t)
{
n++;
cout << t << " ";
}
void printCount()
{
cout << n << endl;
}
public:
int n;
};
下面是一个简单的类成员指针使用,他初始化分为2步在最后给出.:
#include<iostream>
using namespace std;
class T
{
public:
typedef int uint;
public:
int a;
int b;
};
int main21(void)
{
T t;
int T::* t1 = &T::b;//1、成员函数指针 初始化为指向类T成员b的一个指针(成员函数指针指向的是偏移量)
T* t2 = &t;//t2一个指向类变量t的指针
t.*t1 = 10;//2、初始化t的t1类成员指针指向的内存空间值为10,实际上就是t.b=10
cout<<t.*t1<<" "<<t2->*t1<<endl;//相同输出一个采用对象一个采用对象指针
{
T t3;
t3.a=300;
t.*t1 = t3.a; //他就是拥有实际内存空间的变量了
}
}
模板和函数重载就没有什么好说的了。
接下来我们看看UT_LIST_BASE_NODE_T、UT_LIST_NODE_T分别代表了什么
实际上他们都是宏定义:
#define UT_LIST_BASE_NODE_T(t) ut_list_base<t, ut_list_node t::*>
#define UT_LIST_NODE_T(t) ut_list_node
那么他们的类型出来了实际上就是:
ut_list_base和ut_list_node,我们知道在设计链表的时候,通常有一个链表头数据结构,用来存储
比如链表中总共多少元素,链表头,链表尾等等特征,但是之前还是想来看看ut_list_node链表结构体:
template <typename Type>
struct ut_list_node {
Type* prev; /*!< pointer to the previous
node, NULL if start of list */
Type* next; /*!< pointer to next node,
NULL if end of list */
void reverse()
{
Type* tmp = prev;
prev = next;
next = tmp;
}
};
非常简单没有包含任何固定的数据信息,只是包含了链表的前后指针,同时包含了一个成员函数reverse,作为
实现链表反转的基础,这里也注意到由于没有包含任何数据信息成员,做到了链表和具体数据类之间的剥离。
在链表设计的时候通常有2种方式:
1、链表结构包含数据类
2、数据类包含链表结构
这里INNODB使用了后者,让链表的通用更加方便
再来看看ut_list_base 链表头结构体:
template <typename Type, typename NodePtr>
struct ut_list_base {
typedef Type elem_type;
typedef NodePtr node_ptr;
typedef ut_list_node<Type> node_type;
ulint count; /*!< count of nodes in list */
elem_type* start; /*!< pointer to list start,
NULL if empty */
elem_type* end; /*!< pointer to list end,
NULL if empty */
node_ptr node; /*!< Pointer to member field
that is used as a link node */
#ifdef UNIV_DEBUG
ulint init; /*!< UT_LIST_INITIALISED if
the list was initialised with
UT_LIST_INIT() */
#endif /* UNIV_DEBUG */