redis 5.0.7 source code reading - doubly linked list

redis dynamic string sds related files: adlist.h and adlist.c

A data structure

Redis defined in a doubly linked list, with roughly the same ordinary doubly linked list

A single node:

1 typedef struct listNode {
2     struct listNode *prev;
3     struct listNode *next;
4     void *value;
5 } listNode;

List:

1 typedef struct list {
2     listNode *head;
3     listNode *tail;
4     void *(*dup)(void *ptr);
5     void (*free)(void *ptr);
6     int (*match)(void *ptr, void *key);
7     unsigned long len;
8 } list;

A function pointer list, to achieve a replication method polymorphism, and Comparative destruction.

Iterator:

1 typedef struct listIter {
2     listNode *next;
3     int direction;
4 } listIter;

Iterator There is a member variable direction, used to indicate the direction of the current traversal.

General structure:

 1 /*
 2 +-------------------+        +----------------> +--------------+ <-------+
 3 |listNode *head     |--------+                  |listNode *prev|-->NULL  |
 4 +-------------------+                           +--------------+         |
 5 |listNode *tail     |--------+                  |listNode *next|----+    |
 6 +-------------------+        |                  +--------------+    |    |
 7 |void *(*dup)(...)  |        |                  |void *value   |    |    |
 8 +-------------------+        |                  +--------------+    |    |
 9 |void (*free)(...)  |        |                                      |    |
10 +-------------------+        |                                      |    |
11 |int (*match)(...)  |        |                                      |    |
12 +-------------------+        +----------------> +--------------+ <--+    |
13 |unsigned long len  |                           |listNode *prev|---------+
14 +-------------------+                           +--------------+
15                                                 |listNode *next|-->NULL
16                                                 +--------------+
17                                                 |void *value   |
18                                                 +--------------+    
19 */                                            

Second, create

Create an initial doubly linked list redis in relatively simple, as long as the distribution of good memory, and to the member variable initial value on it

 1 list *listCreate(void)
 2 {
 3     struct list *list;
 4 
 5     if ((list = zmalloc(sizeof(*list))) == NULL)
 6         return NULL;
 7     list->head = list->tail = NULL;
 8     list->len = 0;
 9     list->dup = NULL;
10     list->free = NULL;
11     list->match = NULL;
12     return list;
13 }

 

redis head provided interpolation, interpolation and specifying the end position of the insertion node are three ways to add nodes to the linked list, a doubly linked list no different from ordinary, not described in detail here.

Third, the destruction

Because the value for each node in the linked list may point heap space, it can not directly to the list structure is free, this will be a memory leak. Need to first release the value of each node, you can free structure

Clear all nodes:

. 1  void listEmpty (* List List)
 2  {
 . 3      unsigned Long len;
 . 4      listnode Current *, * Next;
 . 5  
. 6      Current = list-> head;
 . 7      len = list-> len;
 . 8      the while (len-- ) {
 . 9          Next to current- => Next;
 10          // if the destruction of the function is specified, the specified function to destroy value 
. 11          IF (list-> Free ) list-> Free (to current-> value);
 12 is          zfree (Current);
 13 is         current = next;
14     }
15     list->head = list->tail = NULL;
16     list->len = 0;
17 }

Destruction list:

1 void listRelease(list *list)
2 {
3     listEmpty(list);
4     zfree(list);
5 }

Similarly, redis provides a list of common operations with the same list to delete a single node, nor do here described.

Fourth, the iterator operation

redis provides an interface to obtain an iterator

 1 listIter *listGetIterator(list *list, int direction)
 2 {
 3     listIter *iter;
 4 
 5     if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
 6     if (direction == AL_START_HEAD)
 7         iter->next = list->head;
 8     else
 9         iter->next = list->tail;
10     iter->direction = direction;
11     return iter;
12 }

In an example AL_START_HEAD generates good iterator following structure:

 

 1 /*
 2 +-------------------+    +---> +--------------+ <-------+----+
 3 |listNode *head     |----+     |listNode *prev|-->NULL  |    |  
 4 +-------------------+          +--------------+         |    |  +--------------+
 5 |listNode *tail     |----+     |listNode *next|----+    |    +--|listNode *next|
 6 +-------------------+    |     +--------------+    |    |       +--------------+
 7 |void *(*dup)(...)  |    |     |void *value   |    |    |       |int direction |
 8 +-------------------+    |     +--------------+    |    |       +--------------+
 9 |void (*free)(...)  |    |                         |    |
10 +-------------------+    |                         |    |
11 |int (*match)(...)  |    |                         |    |
12 +-------------------+    +---> +--------------+ <--+    |
13 |unsigned long len  |          |listNode *prev|---------+
14 +-------------------+          +--------------+
15                                |listNode *next|-->NULL
16                                +--------------+
17                                |void *value   |
18                                +--------------+    
19 */                                                                                

The next method iterator:

 1 listNode *listNext(listIter *iter)
 2 {
 3     listNode *current = iter->next;
 4 
 5     if (current != NULL) {
 6         if (iter->direction == AL_START_HEAD)
 7             iter->next = current->next;
 8         else
 9             iter->next = current->prev;
10     }
11     return current;
12 }

Structure after a call:

 1 /*
 2 +-------------------+    +---> +--------------+ <-------+
 3 |listNode *head     |----+     |listNode *prev|-->NULL  |      
 4 +-------------------+          +--------------+         |       +--------------+
 5 |listNode *tail     |----+     |listNode *next|----+    |    +--|listNode *next|
 6 +-------------------+    |     +--------------+    |    |    |  +--------------+
 7 |void *(*dup)(...)  |    |     |void *value   |    |    |    |  |int direction |
 8 +-------------------+    |     +--------------+    |    |    |  +--------------+
 9 |void (*free)(...)  |    |                         |    |    |
10 +-------------------+    |                         |    |    |
11 |int (*match)(...)  |    |                         |    |    |
12 +-------------------+    +---> +--------------+ <--+----|----+    
13 |unsigned long len  |          |listNode *prev|---------+
14 +-------------------+          +--------------+
15                                |listNode *next|-->NULL
16                                +--------------+
17                                |void *value   |
18                                +--------------+    
19 */                                                                              

Called again:

 1 /*
 2 +-------------------+    +---> +--------------+ <-------+
 3 |listNode *head     |----+     |listNode *prev|-->NULL  |      
 4 +-------------------+          +--------------+         |       +--------------+
 5 |listNode *tail     |----+     |listNode *next|----+    |    +--|listNode *next|
 6 +-------------------+    |     +--------------+    |    |    |  +--------------+
 7 |void *(*dup)(...)  |    |     |void *value   |    |    |    |  |int direction |
 8 +-------------------+    |     +--------------+    |    |    |  +--------------+
 9 |void (*free)(...)  |    |                         |    |    |
10 +-------------------+    |                         |    |    |
11 |int (*match)(...)  |    |                         |    |    |
12 +-------------------+    +---> +--------------+ <--+    |    +-->NULL    
13 |unsigned long len  |          |listNode *prev|---------+
14 +-------------------+          +--------------+
15                                |listNode *next|-->NULL
16                                +--------------+
17                                |void *value   |
18                                +--------------+    
19 */                                                                            

Call the next function returns a value of listNode before calling the first address

Five other operations

redis doubly linked list also provides other operations. Wherein, to find the specified key comparison with copy / replication custom method relies on the use of the entire list iterators, and to use.

In addition, it also provides a similar manner as random read, the internal implementation returns NULL when traversed, and the "out of bounds." At the same time, it supports the index is negative, expressed from the end of the beginning. Similar rotation operation, before the end of the original node moves to the head node becomes the new head node. Of course, there are two lists splicing operation.

 

 

redis 5.0.7 Download Links

http://download.redis.io/releases/redis-5.0.7.tar.gz

Source Reading Order Reference:

https://github.com/huangz1990/blog/blob/master/diary/2014/how-to-read-redis-source-code.rst

Guess you like

Origin www.cnblogs.com/chinxi/p/12233306.html