一、概述

Linux radix树最广泛的用途是用于内存管理,结构address_space通过radix树跟踪绑定到地址映射上的核心页,该radix树允许内存管理代码快速查找标识为dirty或writeback的页。Linux radix树的API函数在lib/radix-tree.c中实现。

Linux基数树(radix tree)是将指针与long整数键值相关联的机制,它存储有效率,并且可快速查询,用于指针与整数值的映射(如:IDR机制)、内存管理等。

上图显示了一个有3级结点的radix树,每个数据条目(item)可用3个6位的键值(key)进行索引,键值从左到右分别代表第1~3层结点位置。没有孩子的结点在图中不出现。因此,radix树为稀疏树提供了有效的存储,代替固定尺寸数组提供了键值到指针的快速查找。
以index=0x5BFB68为例,化为二进制,每6位为一组:10110(22,第一层编号) 111111(63第二次编号) 101101(45第三层编号) 101000(40第四层编号)

二、基本数据结构

struct radix_tree_root {
unsigned int height;
gfp_t gfp_mask;
struct radix_tree_node *rnode;/*间接指针指向结点而非数据条目,通过设置root->rnode的低位表示是否是间指针*/
};

struct radix_tree_node {
unsigned int height; /* 从叶子向上计算的树高度 */
unsigned int count; /*非叶子结点含有一个count域,表示出现在该结点的孩子的数量*/
struct rcu_head rcu_head;
void *slots[RADIX_TREE_MAP_SIZE]; //64个指针,每层64个子节点
unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
//2X2数组,每个成员都为32位,
在结点结构radix_tree_node中,tags域是一个二维数组,每个slot用2位标识,这是一个典型的用空间换时间的应用。tags域用于记录该结点下面的子结点有没有相应的标志位。
//结点标签数组=每个slot需要的最大标签位数*slot数所需的long类型变量数
/*tag[0]64位,2个long类型,每一位代表一个slot,表示其PG_dirty
tag[0]64位,2个long类型,每一位代表一个slot,表示其PG_Writeback
如果当前节点的tags[0]值为1,那么它的子树节点就存在PAGE_CACHE_DIRTY节点,否则这个子树分枝就不存在着这样的节点,就不必再查找这个子树了。比如在查找PG_dirty的页面时,就不需要遍历整个树,而可以跳过那些tags[0]为0值的子树,这样就提高了查找效率*/
};

三、全局定义

#define RADIX_TREE_MAP_SHIFT 6
/*值为6时,表示每个结点有2^6=64个slot,值为4时,表示有2^4=16个slot*/
#define RADIX_TREE_MAP_SIZE (1UL <<RADIX_TREE_MAP_SHIFT) //1000000,2^6=64
/*表示1个叶子结点可映射的页数,如:1<<6=64,表示可映射64个slot映射64页*/
#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) //111111
#define RADIX_TREE_TAG_LONGS \
((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) /BITS_PER_LONG) //(64+32-1)/32=2
#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsignedlong)) //32
#define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
RADIX_TREE_MAP_SHIFT)) //(32+6-1)/6=6
#define RADIX_TREE_MAX_TAGS 2
/*定义slot数占用的long类型长度个数,每个slot用位图1位进行标记,如:64个slot时,值为2*/

static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH + 1]
// 全局数组,在32位机器上,这个数组大小是7,表示每一层的最大有多少个slot
height=0:maxindex=0, 第一层只有一个radix_tree_node
height=1:maxindex=2^6-1, 第二层最多63个
height=2:maxindex=2^12-1,
height=3:maxindex=2^18-1,
height=4:maxindex=2^24-1, 若每个slot为4k,则表示支持64G
height=5:maxindex=2^30-1,
height=6:maxindex=2^32-1, 16T

四、初始化函数

初始化一个名字是name的树根。mask是gfp相关的掩码,在内存管理的时候用到。
#define RADIX_TREE(name, mask)
struct radix_tree_root my_tree;
INIT_RADIX_TREE(my_tree, gfp_mask);
248 void __init radix_tree_init(void)
1249 {
1250 radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
1251 sizeof(struct radix_tree_node), 0, SLAB_PANIC | SLAB_RECLAIM_ACCOUNT,
1253 radix_tree_node_ctor);
1254 radix_tree_init_maxindex();//初始化全局数组height_to_maxindex
1255 hotcpu_notifier(radix_tree_callback, 0);
1256 }

五、插入条目

int radix_tree_insert(struct radix_tree_root *root, unsigned long, void *item);
函数radix_tree_insert插入条目item到树root中,如果插入条目中内存分配错误,将返回错误-ENOMEM。该函数不能覆盖写正存在的条目。如果索引键值index已存在于树中,返回错误-EEXIST。插入操作成功返回0。
对于插入条目操作失败将引起严重问题的场合,下面的一对函数可避免插入操作失败:
int radix_tree_preload(gfp_t gfp_mask);
void radix_tree_preload_end(void);
函数radix_tree_preload尝试用给定的gfp_mask分配足够的内存,保证下一个插入操作不会失败。在调用插入操作函数之前调用此函数,分配的结构将存放在每CPU变量中。函数radix_tree_preload操作成功后,将完毕内核抢占。因此,在插入操作完成之后,用户应调用函数radix_tree_preload_end打开内核抢占。
 六、删除条目
void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
函数radix_tree_delete删除与索引键值index相关的条目,如果删除条目在树中,返回该条目的指针,否则返回NULL。
七、查询条目
/*在树中查找指定键值的条目,查找成功,返回该条目的指针,否则,返回NULL*/
void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index);
/*返回指向slot的指针,该slot含有指向查找到条目的指针*/
void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index);
/*多键值查找,max_items为需要查找的item个数,results表示查询结果。查询时键值索引从first_index开始*/
radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items);

八、标签操作
/*将键值index对应的条目设置标签tag,返回值为设置标签的条目*/
void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag);
/*从键值index对应的条目清除标签tag,返回值为清除标签的条目*/
void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag);
/*检查键值index对应的条目tag是否设置。tag参数为0或者1,表示Dirty位或者WB位
如果键值不存在,返回0,如果键值存在,但标签未设置,返回-1;如果键值存在,且标签已设置,返回1*/
int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag);
/*从first_index起查询树root中标签值为tag的条目,在results中返回*/
unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag);
/*如果树root中有任何条目使用tag标签,返回键值*/
int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);

参考http://blog.csdn.net/joker0910/article/details/8250085

Linux内核Radix Tree(一)的更多相关文章

  1. Linux内核Radix Tree(二)

    1.   并发技术 由于需要页高速缓存是全局的,各进程不停的访问,必须要考虑其并发性能,单纯的对一棵树使用锁导致的大量争用是不能满足速度需要的,Linux中是在遍历树的时候采用一种RCU技术,来实现同 ...

  2. Linux内核Radix Tree(三):API介绍

    1.     单值查找radix_tree_lookup 函数radix_tree_lookup执行查找操作,查找方法是:从叶子到树顶,通过数组索引键值值查看数组元素的方法,一层层地查找slot.其列 ...

  3. Linux 内核中的数据结构:基数树(radix tree)

    转自:https://www.cnblogs.com/wuchanming/p/3824990.html   基数(radix)树 Linux基数树(radix tree)是将指针与long整数键值相 ...

  4. 基数树(radix tree)

    原文   基数(radix)树 Linux基数树(radix tree)是将指针与long整数键值相关联的机制,它存储有效率,并且可快速查询,用于指针与整数值的映射(如:IDR机制).内存管理等.ID ...

  5. 基于tiny4412的Linux内核移植(支持device tree)(三)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  6. 基于tiny4412的Linux内核移植(支持device tree)(一)

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  7. 《Linux内核设计与实现》读书笔记(十六)- 页高速缓存和页回写

    好久没有更新了... 主要内容: 缓存简介 页高速缓存 页回写 1. 缓存简介 在编程中,缓存是很常见也很有效的一种提高程序性能的机制. linux内核也不例外,为了提高I/O性能,也引入了缓存机制, ...

  8. Linux 内核的文件 Cache 管理机制介绍

    Linux 内核的文件 Cache 管理机制介绍 http://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完 ...

  9. Linux 内核的文件 Cache 管理机制介绍-ibm

    https://www.ibm.com/developerworks/cn/linux/l-cache/ 1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使 ...

随机推荐

  1. TableControl大小变化

    TableControl跟随Form大小变化: 选中TableControl,而不是TablePage,右侧Layout: 可以对其设置居上.居下等位置

  2. JavaScript正则表达式快速判断技巧

    这里是JS的正则的一点心得,并不是最完整的规则汇总,更侧重实际运用中的快速判断,初学者接触正则之后往往会被一堆星号括号给弄晕,有了一些速判技巧就能从整体上把握从而不慌乱. JS正则快速判断技巧的核心就 ...

  3. [React Native] Reusable components with required propType

    In this React Native lesson, we will be creating a reusable Badge component. The component will also ...

  4. java复习1 java简单介绍

    在学校的时候.学JAVA学的模棱两可,半知半解.工作以后给我带来了非常大的困扰,所以我须要在学一遍.如今就開始吧... . java[1]是一种能够撰写跨平台应用软件的面向对象的程序设计语言,是由Su ...

  5. 类 ArrayBlockingQueue<E>(一个由数组支持的有界阻塞队列。)

    类型参数: E - 在此 collection 中保持的元素类型 所有已实现的接口: Serializable, Iterable<E>, Collection<E>, Blo ...

  6. (转载)c语言指针学习

    前言 近期俄罗斯的陨石.四月的血月.五月北京的飞雪以及天朝各种血腥和混乱,给人一种不详的预感.佛祖说的末法时期,五浊恶世 ,十恶之世,人再无心法约束,道德沦丧,和现在正好吻合.尤其是在天朝,空气,水, ...

  7. 【转】Android开发之Bitmap的内存优化详解

    本文来源:转载自: http://mobile.51cto.com/abased-410796.htm 在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitma ...

  8. iOS之自定义UITabBar替换系统默认的(添加“+”号按钮)

    自定义UITabBar替换系统默认的,目的是为了在UITabBar中间位置添加一个“+号按钮”,下面我们来聊聊具体的实现. 1.自定义WBTabBar,让其继承自UITabBar,代码如下: // / ...

  9. eclipse创建项目时出现appcompat_v7包及解决办法

    Android开发学习总结(三)--appcompat_v7项目说明 一.appcompat_v7项目说明 今天来说一下appcompat_v7项目的问题,使用eclipse创建Android项目时, ...

  10. B/S的验证控件

    验证控件 首先设置一下框架,设置为.net framework 4.0,在4.5下貌似会报错,设置方法为项目上右键/属性页/找到左侧菜单栏里的生成/将框架版本改为4.0. 一.非空验证:Require ...