Preface first, post a reference link: http://www.redisbook.com/en/latest/internal-datastruct/adlist.html, also really like the author of the article, a guy after 90 really good, basic skills solid, the linked list is one of the core data structures of redis. It is not only used in the internal implementation of redis, it is also one of the underlying implementations of redis list structure. Here we analyze the adlist in redis source code. H and adlist. c Data Structure The redis linked list structure is a typical double-ended linked list doubly linked list implementation. In addition to a void pointer pointing to a value, each node in the linked list has two direction pointers, one pointing to the frontend node and the other pointing to the successor Node
/** Linked list node */typedef struct listnode {// struct listnode * Prev; // subsequent node struct listnode * Next; // value void * value;} listnode;
Each double-ended linked list is encapsulated by a list structure. The list structure has two pointers, one pointing to the head node of the double-ended linked list and the other pointing to the End Node of the table of the double-ended linked list, this feature allows redis to easily execute commands such as rpop lpush:
/** Linked list */typedef struct list {// header pointer listnode * head; // table tail pointer listnode * tail; // number of nodes unsigned long Len; // copy function void * (* DUP) (void * PTR); // release function void (* free) (void * PTR); // Compare function int (* match) (void * PTR, void * Key);} List;
There are also three function pointers dup, free, and match in the linked list structure. These pointers point to the functions used to process different types of values. As for the Len attribute, the number of linked list nodes counters are one of the two-ended linked lists and nodes: List structure and listnode structure, apilist and listnode both have their own APIs, here I will paste it to learn the redis source code (PS: the following code is the code that can be directly compiled and run after redis is rewritten) list * listcreate (void)
/*** Create a new list ** T = O (1) */list * listcreate (void) {struct list * List; // allocate memory list = (struct list *) malloc (sizeof (struct list) for the list structure; If (list = NULL) return NULL; // initialize the property list-> head = List-> tail = NULL; List-> Len = 0; List-> DUP = NULL; List-> free = NULL; list-> match = NULL; return list ;}
Void listrelease (list * List)
/*** Release the entire list ** T = O (N), n is the list length */void listrelease (list * List) {unsigned long Len; listnode * Current, * Next; current = List-> head; Len = List-> Len; while (Len --) {next = Current-> next; // if the list contains its own free method, call the node value if (list-> free) List-> free (current-> value); // then release the node free (current); current = next ;} free (list );}
List * listaddnodehead (list * List, void * value)
/*** Create a node that contains the given value and add it to the header of the List ** T = O (1) */list * listaddnodehead (list * List, void * value) {listnode * node; node = (listnode *) malloc (sizeof (listnode); If (node = NULL) return NULL; node-> value = value; if (list-> Len = 0) {// list of the first node-> head = List-> tail = node; node-> Prev = node-> next = NULL;} else {// not the first node-> Prev = NULL; node-> next = List-> head; list-> head-> Prev = node; List-> head = node;} List-> Len ++; return list ;}
List * listaddnodetail (list * List, void * value)
/*** Create a node that contains the given value and add it to the end of the list table ** T = O (1) */list * listaddnodetail (list * List, void * value) {listnode * node; node = (listnode *) malloc (sizeof (listnode); If (node = NULL) return NULL; if (list-> Len = 0) {// list of the first node-> head = List-> tail = node; node-> Prev = node-> next = NULL;} else {// not the first node-> Prev = List-> tail; node-> next = NULL; list-> tail-> next = node; List-> tail = node;} List-> Len ++; return list ;}
List * listinsertnode (list * List, listnode * old_node, void * value, int after)
/*** Create a node containing value * and insert the new node before or after the old_node according to the instructions of the After parameter. ** T = O (1) */list * listinsertnode (list * List, listnode * old_node, void * value, int after) {listnode * node; node = (listnode *) malloc (sizeof (listnode )); if (node = NULL) return NULL; If (after) {// insert it to the old_node node and then node-> Prev = old_node; node-> next = old_node-> next; // process the End Node of the table if (list-> tail = old_node) {list-> tail = node;} else {// insert it to N before old_node Ode-> next = old_node; node-> Prev = old_node-> Prev; // process the header node if (list-> head = old_node) {list-> head = node ;}/// update the pointer of the front node and the next node (this is a classic place, saving Code) if (node-> Prev! = NULL) {node-> Prev-> next = node;} If (node-> next! = NULL) {node-> next-> Prev = node;} // update the list node list-> Len ++; return list ;}
Void listdelnode (list * List, listnode * node)
/*** Release the specified node in the list ** T = O (1) */void listdelnode (list * List, listnode * node) {// process the front-end node pointer if (node-> PREV) {node-> Prev-> next = node-> next ;} else {list-> head = node-> next;} // process the successor node if (node-> next) {node-> next-> Prev = node-> Prev ;} else {list-> tail = node-> Prev;} // release the node value if (list-> free) List-> free (node-> value ); // release the node free (node); // update the list node Quantity List-> Len --;}
In fact, I am very unfamiliar with the concept of the iterator, because I am a pure C programmer, do not c ++, here I just followed it! Redis implements an iterator for the list structure, which is used to traverse the List table. The structure definition of the iterator is as follows:
/*** Linked list iterator */typedef struct listiter {// next node listnode * Next; // iteration direction int ction;} listiter;
Direction determines whether the iterator iterates backward along the next pointer or forward along the prev pointer. This value can be the al_start_head constant in adlist. h or the al_start_tail constant:
#define AL_START_HEAD 0#define AL_START_TAIL 1
Learn the api implementation of the iterator: listiter * listgetiterator (list * List, int direction)
/*** Create an iterator for the list. The iteration direction is determined by the Direction parameter. ** each time you pair the iterator listnext (), the iterator returns the next node in the list ** T = O (1) */listiter * listgetiterator (list * List, int direction) {listiter * ITER; iter = (listiter *) malloc (sizeof (listiter); If (iter = NULL) return NULL; // depending on the direction of the iterator, point the iterator pointer to the header or end of the table if (Direction = al_start_head) {ITER-> next = List-> head ;} else {ITER-> next = List-> tail;} // record direction ITER-> direction = direction; return ITER ;}
Void listrewind (list * List, listiter * Li)
/*** Reverse the iterator pointer of ITER to the header of the List ** T = O (1) */void listrewind (list * List, listiter * Li) {Li-> next = List-> head; Li-> direction = al_start_head ;}
Void listrewindtail (list * List, listiter * Li)
/*** Reverse the iterator pointer of ITER to the end of the list table ** T = O (1) */void listrewindtail (list * List, listiter * Li) {Li-> next = List-> tail; Li-> direction = al_start_tail ;}
Listnode * listnext (listiter * ITER)
/*** The function either returns the current node or null. Therefore, the common usage is: * iter = listgetiterator (list, <direction> ); * While (node = listnext (ITER ))! = NULL) {* dosomethingwith (listnodevalue (node); *} ** T = O (1) */listnode * listnext (listiter * ITER) {listnode * Current = ITER-> next; If (current! = NULL) {// select the node if (ITER-> direction = al_start_head) ITER-> next = Current-> next Based on the iteration direction; elseiter-> next = Current-> Prev;} Return Current ;}
Summary although I can implement the above code, I have to summarize the code specifications of redis, which is really good !!