freeswitch APR库哈希表
概述
freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性。
哈希表在开发中应用的非常广泛,主要场景是对查询效率要求较高的逻辑,是典型的空间换时间的数据结构实现。
大多数的底层库有各自的哈希表实现方法,那么apr库中对于哈希表究竟是如何实现的呢,其中有什么优点和缺点?
下面我们对apr库的哈希表实现做一个介绍。
环境
centos:CentOS release 7.0 (Final)或以上版本
freeswitch:v1.8.7
GCC:4.8.5
哈希表数据结构
apr库的哈希表源代码文件在libs/apr目录下。
libs\apr\include\apr_hash.h
libs\apr\tables\apr_hash.c
哈希表结构体定义在apr_hash.c中。
struct apr_hash_entry_t {
apr_hash_entry_t *next;
unsigned int hash;
const void *key;
apr_ssize_t klen;
const void *val;
};
struct apr_hash_index_t {
apr_hash_t *ht;
apr_hash_entry_t *this, *next;
unsigned int index;
};
struct apr_hash_t {
apr_pool_t *pool;
apr_hash_entry_t **array;
apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */
unsigned int count, max;
apr_hashfunc_t hash_func;
apr_hash_entry_t *free; /* List of recycled entries */
};
常用函数
查看源代码头文件libs\apr\include\apr_hash.h。
apr_hashfunc_default //默认hash函数
apr_hash_make //创建hash表
apr_hash_make_custom //创建hash表,自定义hash函数
apr_hash_copy //复制hash表
apr_hash_set //hash表插入一个新的键值对
apr_hash_get //hash表查找key对应的value
apr_hash_first //hash表遍历,第一个节点
apr_hash_next //hash表遍历,下一个节点
apr_hash_this //hash表遍历,获取当前节点内容
apr_hash_count //hash表键值对计数
apr_hash_clear //清空所有键值对
apr_hash_overlay //合并俩个hash表
apr_hash_merge //合并俩个hash表,自定义冲突处理函数
apr_hashfunc_default默认哈希函数
apr库哈希表默认的哈希函数使用times33哈希算法,times33算法很简单,就是不断的乘33。
对于字符串类型的key,times33算法很好用,计算很快,hash结果分布均匀。
核心代码如下:
if (*klen == APR_HASH_KEY_STRING) {
for (p = key; *p; p++) {
hash = hash * 33 + *p;
}
*klen = p - key;
}
else {
for (p = key, i = *klen; i; i--, p++) {
hash = hash * 33 + *p;
}
}
apr_hash_make创建
apr库哈希表的创建函数。
1, 从内存池分配apr_hash_t大小的内存。
2, 字段初始化,包括内存池指针赋值,free指针设置为NULL,count设置为0,max为INITIAL_MAX(15), array指针数组内存分配,hash函数使用apr_hashfunc_default。
apr_hash_set插入
apr库哈希表,插入键值对。
1, 查找。根据key计算hash值,并在hash值对应的array[hash & ht->max]下查找key,key已存在则返回当前entry。key不存在,优先从free链表中获取entry,否则新建entry并返回。
2, 检查获取到的entry。如果传入的val值为空,则将该entry删除并加入free链表。传入的val值正常,则替换entry中的val字段。
3, 检查count计数超过max时,扩展哈希表。
4, 扩展哈希表时,创建new_array数组,new_max大小为(max * 2 + 1)。遍历array,赋值到new_array并切换array数组。
apr_hash_get查找
apr哈希表查找的逻辑:
根据key计算hash值,并在hash值对应的array[hash & ht->max]下查找key,key存在则返回当前entry中的val值。key不存在则返回NULL。
apr_hash_clear清空
apr哈希表清空的逻辑:
遍历hash表,把所有的entry节点中的val设置为NULL。
所以,apr_hash_clear之后,hash表并没有清空,只是把所有的entry节点的val置空,并将entry放入了free链表。
总结
apr库的哈希表对于大部分场景已经足够使用了。但是有一些特殊的场景要考虑到出问题的可能。
apr库哈希表不是线程安全的。
apr库哈希表没有对冲突做进一步处理,在array[i]下的entry链表长度超过某个阈值时,通过某些方法降低冲突,比如扩容、修改hash算法、entry使用红黑树代替链表等等。
空空如常
求真得真
freeswitch APR库哈希表的更多相关文章
- freeswitch APR库
概述 freeswitch依赖库源代码基本都可以在libs目录下找到. 在freeswitch的官方手册中,可以找到freeswitch的依赖库表格,其中freeswitch的core核心代码依赖库主 ...
- freeswitch APR库线程读写锁
概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 线程读写锁在多线程服务中有重要的作用.对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率. 由于A ...
- 简单的哈希表实现 C语言
简单的哈希表实现 简单的哈希表实现 原理 哈希表和节点数据结构的定义 初始化和释放哈希表 哈希散列算法 辅助函数strDup 哈希表的插入和修改 哈希表中查找 哈希表元素的移除 哈希表打印 测试一下 ...
- C++ STL中哈希表Map 与 hash_map 介绍
0 为什么需要hash_map 用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能.例如,我要记录一个人名和相应的存储,而且随时增加,要快速查找和修改: 岳不群-华 ...
- python 全栈开发,Day61(库的操作,表的操作,数据类型,数据类型(2),完整性约束)
昨日内容回顾 一.回顾 定义:mysql就是一个基于socket编写的C / S架构的软件 包含: ---服务端软件 - socket服务端 - 本地文件操作 - 解析指令(mysql语句) ---客 ...
- 库的操作&表的操作
一 库的操作 掌握库的增删改查 一.系统数据库 执行如下命令,查看系统库 show databases; information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数 ...
- stl vector、红黑树、set、multiset、map、multimap、迭代器失效、哈希表(hash_table)、hashset、hashmap、unordered_map、list
stl:即标准模板库,该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法 六大组件: 容器.迭代器.算法.仿函数.空间配置器.迭代适配器 迭代器:迭代器(iterator)是一种抽象的设计 ...
- mysql更新(三)语句 库的操作 表的操作
04-初始mysql语句 本节课先对mysql的基本语法初体验. 操作文件夹(库) 增 create database db1 charset utf8; 查 # 查看当前创建的数据库 show ...
- MySQL常见的库操作,表操作,数据操作集锦及一些注意事项
一 库操作(文件夹) 1 数据库命名规则 可以由字母.数字.下划线.@.#.$ 区分大小写 唯一性 不能使用关键字如 create select 不能单独使用数字 最长128位 2 数据库相关操作 创 ...
随机推荐
- TypeError: module() takes at most 2 arguments (3 given)
1. 错误提示 2. 代码 class Parent: """定义父类""" def __init__(self): print(" ...
- 耗时一个月,整理出这份Hadoop吐血宝典
本文目录: 一.HDFS 二.MapReduce 三.Yarn 四.Hadoop3.x 新特性 五.Hadoop 大厂面试真题解析 Hadoop 涉及的知识点如下图所示,本文将逐一讲解: 本文档参考了 ...
- Unity——计时器功能实现
Unity计时器 Demo展示 介绍 游戏中有非常多的计时功能,比如:各种cd,以及需要延时调用的方法: 一般实现有一下几种方式: 1.手动计时 float persistTime = 10f flo ...
- 注解,@Qualifier+@Autowired 和 @Resource
摘要: 项目中,对于AOP的使用,就是通过用注解来注入的. 更改之前的注解,是使用:@Qualifier+@Autowired 但是,通过这样注解,在项目启动阶段,需要自动扫描的过程是非常缓慢的, ...
- 基于jpa的specification实现动态查询
spring data jpa为我们实现简单的crud操作提供了极大的方便.但大部分情况下,系统中都存在大量的动态查询操作,这个时候就可以借助spring data jpa的 Specificatio ...
- spring-cloud-square开发实战(三种类型全覆盖)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 前文<五分钟搞懂spring-clou ...
- C# 如何将日期格式化ISO8601模式
类似于这样的时间戳格式:预计来访时间,时间参数需满足ISO8601格式:yyyy-MM-ddTHH:mm:ss+当前时区,例如北京时间:2018-07-26T15:00:00 + 08:00 stri ...
- 如何系统学习C 语言(中)之 指针篇
谈到指针,我们可能会想到钟表上的指针,但这里的指针不是现实生活中看得见摸得着的钟表上的指针,c 语言中的指针只存在于逻辑思维中,物理上并不存在. 同时,指针也是C 语言中最精华的部分,通过灵活地运用指 ...
- Language Server for Java™ 1.0 在VS Code上正式发布!
Nick Zhu form Senior Program Manager, Developer Division at Microsoft 今天,我们很高兴与大家宣布:Language Server ...
- MySQL到底能否解决幻读问题
先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...