Memory management of red and black trees

Source: Internet
Author: User
Citation Link: http://www.kerneltravel.net/jiaoliu/kern-rbtree.html

Red black tree is a balanced binary tree, it has a very good nature, the nodes in the tree are orderly, and because it is balanced, so the search will not appear very bad situation, based on binary tree operation time complexity is O (log (N)). The Linux kernel uses red-black trees to maintain memory blocks when it manages vm_area_struct.

Let's go to include/linux/rbtree.h. Some definitions of the red and black trees are as follows:



struct Rb_root is just a wrapper for struct rb_node*, and the advantage is that it doesn't seem to pass a level two pointer. Yes, it's simple. Look at the following several important macros, careful you will find that Rb_parent_color is actually not so simple, Andrea Arcangeli used a small trick here, but very good. As the name implies, this member actually contains a pointer to the parent and the color of the node. How did it do that? Very simple, alignment plays a role. Since is the size of sizeof (long) alignment, then on the IA-32, any rb_node structure of the address of the low two bits is definitely zero, and with the empty, rather than use them to represent the color, anyway, the color of two, in fact, one is enough.

In this way, the parent pointer is extracted as long as the lower two bits of the Rb_parent_color member are cleared 0:

#define Rb_parent (R) ((struct Rb_node *) ((r)->rb_parent_color & ~)


Take the color as long as you see the last one:
#define RB_COLOR (R) (r)->rb_parent_color & 1)


testing colors and setting colors is a matter of the same thing. One of the following inline functions to be particularly noted:

static inline void Rb_link_node (struct rb_node * node, struct Rb_node * parent, struct Rb_node * * rb_link);


It sets parent to node's parent node, and Rb_link points to node.

We focus on lib/rbtree.c and look at some important algorithms related to red and black trees. Before we begin, let's recall the rules of the red-black tree:


1. Each node is either red or black;

2. The root node must be black;

3. Red Junction If there are children, their children must all 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 sorting tree to be balanced.

__rb_rotate_left is the node node in the tree rooted in root is left-handed, and the __rb_rotate_right is right-handed. These two functions are for the subsequent insert and delete services, and not for the externally supplied interfaces.

The newly inserted nodes are set as leaves, dyed red, and if broken by the above rules after insertion, the binary tree is re-balanced by adjusting the color and rotation to restore. The interface function for the insert operation is

void Rb_insert_color (struct rb_node *node, struct rb_root *root);


It incorporates the node node of the identified parent node into the root-rooted red-black tree, and the analysis of the algorithm can be referred to in section 14.3 of [1], where the implementation is almost identical to the explanation in the book. How to determine if node's parent node should be completed 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 is no more than two times. So the efficiency is still very optimistic.

The delete operation is more or less troublesome, it first performs a "delete" like a normal binary search tree, and then determines whether to perform further operations based on the color of the deleted node. The interfaces that are removed are:

void Rb_erase (struct rb_node *node, struct rb_root *root);


In fact, it does not really delete node, but just let it and root-rooted tree out of the relationship, and finally it will determine whether to invoke __rb_erase_color to adjust. The specific algorithm of the explanation of reference [1] in sections 13.3 and 14.4, __rb_erase_color corresponding to the book of Rb-delete-fixup, the implementation here and the book is basically the same.

The rest of the interfaces are relatively simple.

struct Rb_node *rb_first (struct rb_root *root);


Find and return the smallest node in the root-rooted tree as long as you go from the root node to the left.

struct Rb_node *rb_last (struct rb_root *root);


is to find and return the largest one, always go right.

struct Rb_node *rb_next (struct rb_node *node);


Returns the successor of node in the tree, which is slightly more complicated. 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 and finds that the overlapping node is the node of its father's left child, returning the parent node. Returns null if the root node has been reached at all points.

struct Rb_node *rb_prev (struct rb_node *node);


Returns the predecessor of node, and the symmetry of the operation in Rb_next.

void Rb_replace_node (struct rb_node *victim, struct rb_node *new, struct rb_root *root);


Replace the victim node in the root-rooted tree with new.

A typical example of the use of red-black tree interfaces 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 these good properties 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.

Resources:

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.

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.