Redis是一个正在进行中的开源键值数据库项目,作者是antirez。redis与一般键值数据库相比,其最大特色是键值对中的值支持链表、集合、排序集等复合结构。这里我们来看看antirez是怎样实现通用链表结构的。

如果你熟悉Linux,应该知道Linux内核也实现了通用链表结构,它使用了GCC中超越了ANSI C规范的特性。但是Redis没有这样做,而是使用了类似C++ STL的做法。Redis实现的是双向非循环链表,牵涉到三种数据结构:结点listNode、迭代器listIter、链表本身list。代码如下。 

typedef struct listNode {
void *value;
struct listNode *prev;
struct listNode *next;
}listNode;

 value指向具体的数据,从后面两个指针可以看出这是个双向链表,至于是否循环要从其他代码判断。

 

typedef struct listIter {
struct listNode *next;
int direction;
}listIter;

这是个迭代器,当然需要一个指针来指向结点咯,就是next;direction表示该迭代器的前进方向,AL_START_HEAD表示从头开始,AL_START_TAIL表示从尾开始。



好,链表结构是时候出来了

adlist.h
typedef struct list {
listNode
*head;
listNode
*tail;

void* (*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void*key);

unsigned
int len;
}list;

head、tail和len很好理解,中间三个变量是干嘛的呢,它们是函数变量,dup是复制函数,你可以自己定义复制策略,free是释放策略,match是如何在链表中查询内容的策略。



与链表相关的数据结构就是这三个,下面来看看此链表的API是如何实现的,API详情可查看adlist.h文件。

 

list* listCreate(void);  毫无疑问这是链表的构造函数

adlist.c
list* listCreate(void)
{
struct list *list;
if ((list = zmalloc(sizeof(*list))) == NULL)
return NULL;

list
->head = list->tail = NULL;
list
->len = 0;
list
->dup = NULL;
list
->free = NULL;
list
->match = NULL;

return list;
}

没什么好说的,从堆中动态分配一个list结构,初始化成员变量,然后返回list的指针,这样我们就能控制堆中的链表了。注意zmalloc是Redis自己封装的内存分配函数,如果感兴趣可以查看zmalloc.c文件



有构造函数,就自然有析构函数了,如下:
void listRelease(list *list)

void listRelease(list *list)
{
unsigned
int len;
listNode
*current, *next;

current
= list->head;
len
= list->len;
while (len--) {
next
= current->next;
if (list->free) list->free(current->value);
zfree(current);
current
= next;
}
zfree(list);
}

相关文章:

  • 2021-09-01
  • 2021-05-18
  • 2021-09-06
  • 2022-03-03
  • 2021-12-05
  • 2022-01-21
  • 2021-11-19
  • 2022-02-08
猜你喜欢
  • 2021-04-20
  • 2021-07-10
  • 2021-10-24
  • 2021-07-13
  • 2021-06-16
  • 2022-03-02
  • 2022-12-23
相关资源
相似解决方案