Redis source Profiling (eight) linked list

Source: Internet
Author: User
Tags prev redis reset

In the previous introduction to Redis, you can see that the list is used very often.

A linked list can act as a separate storage structure, such as a client's watch list that records all the keys that the client monitors, and the server's modal subscription list records all clients and its schema subscriptions.

A linked list can also be embedded into a dictionary as a value type in a dictionary, such as a database's monitoring dictionary that uses a linked list to store all clients that monitor a key, and the server's subscription dictionary uses a linked list to store all clients that subscribe to a channel. Linked list Structure node

The linked list in Redis is a doubly linked list, which means that each node holds its predecessor and successor nodes for increased operational efficiency. The nodes are defined as follows

Adlist.h
/* List node *
/typedef struct LISTNODE {
    struct listnode *prev;/* Precursor node *
    /struct ListNode *next; * Successor node */
    void *value;    /* value */
} ListNode;
Linked list

The linked list structure mainly records the table head node and the footer node, the number of nodes and some function pointers, defined as follows

Adlist.h/
* list */
typedef struct LIST {
    listnode *head;/* Link Header node */
    ListNode *tail;/* Link footer node */
  
   void * (*dup) (void *ptr); /* Node value copy function */
    void (*free) (void *ptr);/* Node value destructor */
    Int (*match) (void *ptr, void *key);/* Node value matching function */
    Unsi gned long Len; /* Linked list length */
} list;
  

function pointers are primarily operations on node values, including copying, destructors, and determining whether an equal iterator

In addition, Redis provides iterators for linked lists, primarily for the encapsulation of linked list nodes, as well as to easily move forward and backward through the predecessor and successor nodes of the linked list node.

Adlist.h/
* iterator */
typedef struct LISTITER {/
    * points to the actual node */
    ListNode *next;
    /* Iterator direction, forward or backward */
    int direction;
} Listiter;

The value of direction is two, forward and backward, as defined by a macro

Adlist.h
#define AL_START_HEAD 0/* From beginning to end (back)/
#define AL_START_TAIL 1/* from tail to head (forward) */
Linked list Operations Create a linked list

The creation of a linked list is done by the Listcreate function, which is actually applying the list memory and initializing the member variable

ADLIST.C
/* Create an empty list *
/list *listcreate (void)
{
    struct list *list;

    /* Request memory for linked list *
    /if (list = Zmalloc (sizeof (*list)) = = null)
        return null;
    /* Initialize */
    List->head = List->tail = NULL;
    List->len = 0;
    List->dup = NULL;
    List->free = NULL;
    List->match = NULL;
    return list;
}
Delete a linked list

Deleting a linked list is a little trickier than creating it, because the values saved in each node need to be freed, and that's exactly what the call to the free function does.

ADLIST.C
/* Release the memory space of the list *
/void Listrelease (list *list)
{
    unsigned long len;
    ListNode *current, *next;

    Current = list->head;
    Len = list->len;
    /* Walk through the list and release each node */while
    (len--) {/
        * record the next node */
        next = current->next;
        /* If the node value destructor is defined, call */if
        (list->free) list->free (current->value);
        /* Release node Memory *
        /Zfree (current);
        current = next;
    }
    /* Because list* is also a dynamic application, you also need to release *
    /Zfree (list);
}
Insert node at end

In the implementation of other modules, we often see the operation of adding a node to the tail of the linked list, and its implementation is done by Listaddnodetail. The function first requests the memory for the new node, and then adds the node to the linked list, where the list is empty according to whether the list is empty, the new node will be the head node and the tail node of the list, the precursor and subsequent pointers of the new node are empty, and the new node will be the tail node of the linked list. The successor pointer to the previous tail node points to the new node, and the new node's predecessor pointer points to the previous tail node

ADLIST.C
/* Add nodes at the end of the list *
/list *listaddnodetail (list *list, void *value)
{
    ListNode *node;

    /* Apply node */
    if (node = zmalloc (sizeof (*node)) = = null)
        return null;
    /* Record node value */
    node->value = value;
    /* If the previously linked list is empty, insert a node with the rear end node as a new node *
    /if (List->len = = 0) {
        list->head = list->tail = node;
        /* Set precursor successor */
        Node->prev = Node->next = NULL;
    } else {/
        * not empty, only change tail node */
        Node->prev = LIST-&G T;tail;
        Node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    /* Number of nodes plus one */
    list->len++;
    return list;
}
iterator Movement

Iterators are mainly used to traverse the list, and the focus of the iterator is moving, through the direction variable, you can know the direction of the iterator movement, and through the predecessor node of the linked list node, can easily implement the mobile operation

The adlist.c
/* Moves the iterator while returning the next node *
/ListNode *listnext (listiter *iter)
{/
    * Next pointer is the node pointer that the current iterator points to *
    / ListNode *current = iter->next;

    if (current! = NULL) {/
        * is assigned next according to direction *
        /if (iter->direction = = al_start_head)
            Iter->next = Current-> ; next;
        else
            Iter->next = current->prev;
    }
    /* Returns the node pointed to by the previous iterator */return current
    ;
}
resetting iterators

In addition, Redis provides the action to reset the iterator, which is done by the Listrewind and Listrewindtail functions, respectively

/* Reset iterator direction from start to end, so that the iterator points to the head node *
/void Listrewind (list *list, Listiter *li) {
    Li->next = list->head;
    Li->direction = Al_start_head;
}

/* Reset iterator direction from tail to end, make iterator point to tail node *
/void Listrewindtail (list *list, Listiter *li) {
    Li->next = list->tail;
    Li->direction = Al_start_tail;
}
Linked List Search

With the foundation of the iterator, you can implement the list search function, that is, to find a node in the list that matches a value, you need to iterate through the linked list

ADLIST.C
/* Lookup value key, return list node *
/ListNode *listsearchkey (list *list, void *key)
{
    listiter iter;
    ListNode *node;

    /* Set the iterator direction to start from start to end, making it point to the list header node *
    /Listrewind (list, &iter);
    /* Iterate through the list *
    /while ((node = Listnext (&iter)) = NULL) {/
        * If a value matching function is provided, otherwise use = = Compare *
        /if (List->match) {
            if (List->match (Node->value, key)) {
                return node;
            }
        } else {
            if (key = = Node->value) {
                return node;}}
    }
    return NULL;
}
macro definition Functions

In addition to the functions mentioned above, Redis also provides a number of macro-defined functions, such as returning node values, returning the predecessor nodes of a node, etc.

Adlist.h/* Returns the number of nodes in the list */#define LISTLENGTH (L)
((L)->len)/
* Return to head node */
#define LISTFIRST (L) ((L)- >head)/
* Return to tail node */#define LISTLAST (L)
((l)->tail)/
* Return to precursor node */
#define LISTPREVNODE (n) ((n)- >prev)
/* Returns the successor/*
#define LISTNEXTNODE (n) ((n)->next)/
* Returns the node value */
#define LISTNODEVALUE (N) ( (n)->value)//

Set the value of the linked list copy, value destruction, value matching function */
#define LISTSETDUPMETHOD (L,m) ((l)->dup = (m))
#define Listsetfreemethod (L,m) ((l)->free = (m))
#define Listsetmatchmethod (L,m) ((l)->match = (m))/

* Get value assignment, value destructor, value match function/#define LISTGETDUPMETHOD (L) (l)
->dup)
#define LISTGETFREE (L) ((l)->free)
#define LISTGETMATCHMETHOD (L) ((l)->match)
Summary

Because the structure of the list is simple, it is very easy to understand the implementation. Of course, there are a lot of functions related to the list in Redis, here are just a few of the common operations, interested in the deep source to see

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.