From:http://www.kerneltravel.net/jiaoliu/kern-rbtree.html
red and black trees in Linux kernel
Author: Western Mail Wang Cong
The red-black tree is a kind of balanced binary tree, it has a very good nature, the nodes in the tree are orderly, and because it is balanced, so the lookup will not appear very bad situation, based on the binary tree operation of the time complexity is O (log (N)). The Linux kernel uses a red-black tree to maintain memory blocks when managing vm_area_struct.
Let's go to include/linux/rbtree.h and look at some definitions of the red and black trees, as follows:
struct Rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct Rb_node *rb_right;
struct Rb_node *rb_left;
} __attribute__ ((Aligned (sizeof (long)));
struct Rb_root is only a struct rb_node* package, the advantage of this is that it does not seem to pass a level two pointer. Yes, very simple. Take a look at the following important macro, carefully you will find that Rb_parent_color is not so simple, Andrea Arcangeli here using a small skill, but very good. As the name implies, this member actually contains the pointer to parent and the color of the node. How did it do that? It's simple, it works. Since it is the sizeof (long) size of the alignment, then on the IA-32, any rb_node structure of the address of the lower two bits must be zero, rather than empty, but also use them to represent color, anyway, the color of two, in fact, one is enough.
In this way, the parent pointer is extracted as long as the Rb_parent_color member's low two-digit 0 can be:
#define Rb_parent (R) (struct Rb_node *) ((r)->rb_parent_color & ~3))
Take the color, just look at the last one:
#define RB_COLOR (R) (r)->rb_parent_color & 1)
testing colors and setting colors is a matter of the same. One of the following inline functions that you need to highlight is:
static inline void Rb_link_node (struct rb_node * node, struct Rb_node * parent, struct Rb_node * * rb_link);
It sets the parent to node, and the Rb_link points to node.
Let's focus on the lib/rbtree.c and look at some important algorithms related to the red and black trees. Before we begin, let's recall the rules of the red and black trees:
1. Each node is either red or black;
2. The root node must be black;
3. Red Knot If there is a child, the child must be black;
4. Each path from the root node to the leaf must contain the same number of black nodes.
These four rules can limit a sort tree to be balanced.
The __rb_rotate_left is to rotate the node node of the tree rooted in root to the left, and the __rb_rotate_right is to rotate the right. These two functions are for the subsequent insert and Delete service, not for the external interface.
The new inserted node is set to the leaves, dyed red, if the insertion after the destruction of the rules, by adjusting the color and rotation can be restored, the binary tree and rebalance. The interface function of the insert operation is
void Rb_insert_color (struct rb_node *node, struct rb_root);
It incorporates the node node of the determined parent node into the root-rooted red-black tree, and the analysis of the specific algorithm can refer to section 14.3 of [1] , where the implementation is almost exactly the same as that in the book. How to determine that node's parent node should be completed manually by hand before calling Rb_insert_color. It is worth pointing out that although the insert operation requires a loop iteration, the total number of rotations does not exceed two times. So the efficiency is still very optimistic.
The delete operation is more or less troublesome, it first performs a "delete" like the normal binary lookup tree, and then determines whether to perform further operations based on the color of the deleted node. The removed interfaces are:
void Rb_erase (struct rb_node *node, struct rb_root);
Instead of actually deleting node, it just lets it detach itself from the tree rooted in root, and finally it's going to decide whether to call __rb_erase_color to adjust. The specific algorithm for the interpretation of the reference [1] in sections 13.3 and 14.4, __rb_erase_color Correspondence Book of the Rb-delete-fixup, here the implementation and the book is basically consistent.
The remaining few interfaces are simpler.
struct Rb_node *rb_first (struct rb_root *root);
Find and return the smallest node in a tree rooted in root, just go left from the root node.
struct Rb_node *rb_last (struct rb_root *root);
is to find and return the largest one and go straight to the right.
struct Rb_node *rb_next (struct rb_node *node);
It's a little more complicated to return node's successor in the tree. If node's right child is not empty, it simply returns the smallest node in the right subtree of node, and if it is empty, it looks up to find the node of the iteration that is the parent's left child's knot, and returns the node. Returns null if the root node has been above.
struct Rb_node *rb_prev (struct rb_node *node);
Returns the predecessor of node and the symmetry of operations in Rb_next.
void Rb_replace_node (struct rb_node *victim, struct rb_node *new, struct rb_root);
Replaces the victim node in a tree rooted with root with new.
A typical example of the use of the red-black tree interface is as follows:
Static inline struct page * Rb_search_page_cache (struct inode * inode,
unsigned long offset)
{
struct Rb_node * n = inode->i_rb_page_cache.rb_node;
struct page * page;
while (n)
{
page = Rb_entry (n, struct page, rb_page_cache);
if (Offset < page->offset)
n = n->rb_left;
else if (Offset > Page->offset)
n = n->rb_right;
Else
return page;
}
return NULL;
}
Static inline struct page * __rb_insert_page_cache (struct inode * inode,
unsigned long offset,
struct Rb_node * node)
{
struct Rb_node * * p = &inode->i_rb_page_cache.rb_node;
struct Rb_node * parent = NULL;
struct page * page;
while (*P)
{
parent = *p;
page = rb_entry (parent, struct page, rb_page_cache);
if (Offset < page->offset)
p = & (*p)->rb_left;
else if (Offset > Page->offset)
p = & (*p)->rb_right;
Else
return page;
}
Rb_link_node (node, parent, p);
return NULL;
}
Static inline struct page * Rb_insert_page_cache (struct inode * inode,
unsigned long offset,
struct Rb_node * node)
{
struct page * RET;
if (ret = __rb_insert_page_cache (inode, offset, node))
Goto out;
Rb_insert_color (node, &inode->i_rb_page_cache);
Out
return ret;
}
Because of the good nature of the red-black tree and the simplicity of the interface in the implementation, it is widely used in kernel programming, which greatly improves the efficiency of the kernel.
reference materials:
1. Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest, MIT Press.
2. Understanding the Linux Kernel, 3rd Edition, Daniel P. Bovet, Marco Cesati, O ' Reilly.
3. Linux Kernel 2.6.19 source code.