Radix tree/IDR/IDA
来源:互联网 发布:2016软件人均产值 编辑:程序博客网 时间:2024/05/20 08:42
Radix tree
原理
利用radix tree可以根据一个长整形快速查找其对应的对象指针。radix树与trie树有点相似,trie树一般用于字符串到对象的映射,radix树一般用于长整数到对象的映射。
来看一个四叉radix树,树高为4,每一个根节点最多有四个叶节点,总共最多有256个节点。而且这里每个叶节点使用两个字母(00/01/10/11)表示,一层层下来,由于总共有4层,每个长整型一定是0x00000010类似的8个字母组成的数据。
当我们插入一个新节点的时候,我们根据数据的比特位,在树中向下查找,若没有相应的节点,则生成相应的节点,直到数据比特位访问完,则建立叶节点映射相应的对象。
当我们删除一个节点的时候,沿着路径查找到叶节点后,直接删除叶节点,中间的非叶节点不删除。
结构体及API介绍
linux内核中相关的文件include/linux/radix-tree.h和lib/radix-tree.c,使用时包含头文件#include<linux/radix-tree.h>
radix树的root节点的结构体
struct radix_tree_root { unsigned int height;//从叶节点向上计算出的树高度 gfp_t gfp_mask;//内存申请的标识 struct radix_tree_node __rcu *rnode;//子节点指针};
radix树叶子节点的结构体
struct radix_tree_node { unsigned int height;/* Height from the bottom */ unsigned int count;//子节点个数 union { struct radix_tree_node *parent;//父节点指针 struct rcu_head rcu_head;//用于节点释放的RCU链表 }; void __rcu *slots[RADIX_TREE_MAP_SIZE];//指向存储数据指针 unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];};
初始化
#define RADIX_TREE_INIT(mask) { \ .height = 0, \ .gfp_mask = (mask), \ .rnode = NULL, \}#define RADIX_TREE(name, mask) \ struct radix_tree_root name = RADIX_TREE_INIT(mask)
或者使用
先定义struct radix_tree_root my_radix_tree;变量之后,再使用下面的宏对这个变量初始化。
#define INIT_RADIX_TREE(root, mask) \do { \ (root)->height = 0; \ (root)->gfp_mask = (mask); \ (root)->rnode = NULL; \} while (0)
节点的插入与删除与查找
int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);void *radix_tree_delete(struct radix_tree_root *, unsigned long);void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
例子
IDR
IDR机制是内核中将一个整数ID号和指针关联在一起的机制。
比如,当适配器要访问总线上的I2C设备时,首先要知道他们的ID号,同时要在内核中建立一个用于描述该设备的设备结构体,驱动程序将ID号和设备结构体关联起来,如果使用数组进行索引,一旦ID号很大,则用数组索引会占据大量的存储空间,如果使用链表,在总线上设备特别多的情况下,链表的查询效率不高。此时,IDR机制应运而生,内部采用红黑树,可以很方便的将整数和指针关联起来,并且有很高的搜索效率。
下面是linux/idr.h头文件中的一些定义,具体的函数调用接口可能随着新的内核已经发生了改变,要根据对应的include/idr.h头文件中的定义来。
相关结构体
struct idr { struct idr_layer __rcu *hint; /* the last layer allocated from */ struct idr_layer __rcu *top; struct idr_layer *id_free; int layers; /* only valid w/o concurrent changes */ int id_free_cnt; int cur; /* current pos for cyclic allocation */ spinlock_t lock;};struct idr_layer { int prefix; /* the ID prefix of this idr_layer */ DECLARE_BITMAP(bitmap, IDR_SIZE); /* A zero bit means "space here" */ struct idr_layer __rcu *ary[1<<IDR_BITS]; int count; /* When zero, we can release it */ int layer; /* distance from leaf */ struct rcu_head rcu_head;};
定义并初始化
//定义#define DEFINE_IDR(name) struct idr name = IDR_INIT(name)//静态初始化#define IDR_INIT(name) \{ \ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \}//动态初始化void idr_init(struct idr *idp);
分配存放ID号的内存 int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
将ID号和指针关联 int idr_get_new(struct idr *idp, void *ptr, int *id)
参数ptr是需要关联的指针,参数id是由内核自动分配的ID号
通过ID号查找对应的指针 void *idr_find(struct idr *idr, int id)
删除ID号 void idr_remove(struct idr *idp, int id);
IDA
ida只是用来分配id,并不将某数据结构和id关联起来。
sd设备的设备名,如sda,驱动在生成设备文件的时候会向系统申请一个ida,也就是唯一id,然后把id映射成设备文件名sdxxx,
#define DEFINE_IDA(name) struct ida name = IDA_INIT(name)#define IDA_INIT(name) { .idr = IDR_INIT((name).idr), .free_bitmap = NULL, }void ida_init(struct ida *ida);int ida_pre_get(struct ida *ida, gfp_t gfp_mask);int ida_get_new(struct ida *ida, int *p_id);void ida_remove(struct ida *ida, int id);void ida_destroy(struct ida *ida);
参考文章
- IDR机制
- Radix tree/IDR/IDA
- idr 机制 radix tree
- idr and radix-tree
- radix tree
- Radix TRee
- Radix树 与 Linux IDR机制
- address_space 与 radix tree
- radix tree 基数树
- 基数树(radix tree)
- 基数树(radix tree)
- Radix tree--reference
- 基数树(radix tree)
- 基数树(radix tree)
- Linux内核Radix Tree
- 基数树(radix tree)
- 基数树(radix tree)
- 基数树(Radix Tree)
- radix tree 整理
- MySQL使用全文索引(fulltext index)
- java序列化
- 上机5
- css捋一捋
- 课后4
- Radix tree/IDR/IDA
- android静态库
- 操作系统虚拟内存的作用概括
- opencv3错误集锦(一)——无法打开包括文件:"opencv2/opencv.hpp": No such file or directory
- 加盟申请表
- iOS 异步请求等待传值方法小结
- org.junit 注解
- Redis 简介
- 如何保证http传输安全性