动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
电脑书籍下载:程序设计书籍 | 数据库教程书籍 | 平面与多媒体书籍 | 网络通讯书籍 | 系统管理书籍 | 网络安全书籍 | 认证考试书籍
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > 软件工程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ 软件工程 ]的信息



本月文章推荐
.让ESB与SOA同步.
.UML在嵌入式系统设计中的应用.
.对Windows .NET Server的评估.
.XAML开发入门之开发环境介绍.
.在IBM WebSphere MQ本地队列中存.
.IT 架构和应用程序的端到端测试.
..NET架构与模式探索.
.新上任项目经理遇到的难题.
.项目管理中需要处理好的四个问题.
.基于CMM实施软件过程改进的成功策.
.Windows 2000 Professional中用命.
.COM, COM+ and .NET 的区别.
.在.NET中使用命名管道完成进程间.
.软件开发质量管理层次模型(1).
.面向服务的架构SOA的推荐方法.
.IBM的MARS加密算法实现(1).
.统一建模语言UML简介.
.嵌入式系统:后PC时代的擎天之柱.
..NET Server 2003中的Microsoft群.
.在Avalon中建立数据识别的应用程.

Apache中的表格实现剖析(2)

发表日期:2008-3-23 |


3.2.3表格元素查找
    表格元素查找是表格的一个非常重要的功能。目前存在很多的线性表查找算法,最基本的无非三种:顺序查找,二分查找以及哈希查找。相对而言,顺序查找是最简单也是最轻易实现,但是其通常在插入数据时候较为快捷,而查找的时候则就相对较慢。二分查找是一个较快的查找方法,但是其前提必须数据进行排序,因此排序使得插入较慢,因此也不是所有场合均适合。而哈希查找则既实现简单,又插入和查找速度较快。因此在Apache中队表格的插入和查找则采取了哈希算法。
Apache中在表格中查找一个键值为key的元素的函数为apr_table_get,其定义如下:
APR_DECLARE(const char *) apr_table_get(const apr_table_t *t, const char *key)
{
    apr_table_entry_t *next_elt;
    apr_table_entry_t *end_elt;
    apr_uint32_t checksum;
    int hash;
 
    if (key == NULL) {
     return NULL;
    }
    hash = TABLE_HASH(key);
    if (!TABLE_INDEX_IS_INITIALIZED(t, hash)) {
        return NULL;
    }
    COMPUTE_KEY_CHECKSUM(key, checksum);
    next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];;
    end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash];
 
    for (; next_elt <= end_elt; next_elt++) {
     if ((checksum == next_elt->key_checksum) &&
            !strcasecmp(next_elt->key, key)) {
         return next_elt->val;
     }
    }
    return NULL;
}
    正如前面的apr_table_entry_t中看到的,对于表格中的每一个元素我们都维护一个key成员,为字符指针变量,该key用来标识该元素,在Apache中由于答应重复key的存在,因此在表格中可能存在多个key相同的元素,不过apr_table_get函数只返回查找到的第一个符合要求的元素。
    对于任何一个键值,我们可以通过TABLE_HASH(key)找到对应元素在表格中存放的索引。 TABLE_HASH为一个宏,定义为(TABLE_INDEX_MASK & *(unsigned char *)(key))。一旦得到哈希索引hash,函数将判定该索引所定应的内存块是否已经被初始化。假如该索引块还没有初始化,则理所当然,里面什么都没有,也就没法取了,此时直接返回NULL。
    当然假如内存中确实有“货”可用,则函数将进一步调用宏COMPUTE_KEY_CHECKSUM(key, checksum)来计算键值key所对应的校验值,校验结果即为checksum,该checksum主要作为宏TABLE_HASH的参数。
现在我们再往返顾前面提到的apr_table_t中的剩余的两个辅助成员变量:
int index_first[TABLE_HASH_SIZE];
int index_last[TABLE_HASH_SIZE];
    前面我们提到这二个辅助成员主要用在加速对表格中成员的查找,那么我们现在看看这两个成员变量是如何实现查找加速的。
    我们首先来看宏TABLE_HASH(key)的实现:
    #define TABLE_HASH(key) (TABLE_INDEX_MASK & *(unsigned char *)(key))
    从上面的哈希值得计算中可以看出,不管对于任何一个键值key,只有该键值的第一个字母参与了运算,因此比如对于“hello”和“house”而言,其计算出来的结果都是8。我们将整个表格分为多个“类别”,这些类别通过TABLE_HASH(key)进行区分,实际上也就是按照key的第一个字母进行分类。因此“hello”和“house”属于同一个类,而和“cat”则属于不同的类别。Apache中对键值的查找是基于类别进行的。假如一个类别在表格中具有多个元素,那么毫无疑问,肯定就发生了哈希冲突。

    为了解决索引冲突的问题,apr_table_t中引入index_first和index_last数组,分别记录给定的类别在表格中的起始索引和终止索引。对于某个类别,比如“h”类别(所有的以h开始的键值都属于这个类),它在index_first和index_last中的索引可以通过TABLE_HASH(key)计算得到,结果为8。因此整个表格中第一个h类元素在表格中的索引保存在index_first[8](即index_first[TABLE_HASH(key)]中,而最后一个h类的成员的索引则保存在index_last[8]中。同理假如对于“c”类别,它的TABLE_HASH(key)为3,因此整个表格的第一个c类元素的索引则保存在index_first[3]中,最后一个在保存在index_last[3]中。
Apache中的表格实现剖析(2)
    比如,目前在表格中仅存在三个键值以字母h开头,分别为“house”、“hello”、“horse”,它们在表格中的索引分别为7、9、12,同时还存在四个以c开始的键值,分别是“cat”、“copy”、“catch”、“cite”,它们在表格中的索引分别为5、6、8、10。对于h类而言,它们对应的index_first中的索引为8,值为7,意味着所有的以h开始的键值第一次出现是在表格的索引为7的位置,同样从上表可以看出,所有以c开始的键值第一次出现是在表格的索引为5的位置。同样对于h类而言,它们对应的index_last中的索引也是8,值为12,意味着表格中最后一个以h开始的键值在表格中的索引为12,同时,表格中的最后一个以c起始的键值的索引是10。
    假如现在需要查找”hello”,经过COMPUTE_KEY_CHECKSUM(key, checksum)计算后,它的checksum为8。因此函数此时将检查index_first[8]和index_last[8]中的数据,如图,分别为7和11。这意味着所有的以’h’开始的键值都在表格的第 7和第11之间,因此此时只需要搜索索引从7到11的元素就可以了。
    一旦明确index_first和index_last数组的用途,我们就可以使用这两个数组加快搜索速度。比如假如需要搜索“hello”,我们不再需要从第一个元素查找到最后一个元素,相反,我们仅仅需要搜索表格中索引位于index_first[TABLE_HASH(“hello”)]和index_last[TABLE_HASH(“hello”)]之间的元素,即表格中第7个和第12个之间的元素。通过这种策略,可以大大缩小查询的范围。对于缩小范围之内的查找,我们则使用普通的查找方法,逐一比较。
上述算法的实现代码如下:
next_elt = ((apr_table_entry_t *) t->a.elts) + t->index_first[hash];;
end_elt = ((apr_table_entry_t *) t->a.elts) + t->index_last[hash];
for (; next_elt <= end_elt; next_elt++)
{
if ((checksum == next_elt->key_checksum) &&!strcasecmp(next_elt->key, key))
{
return next_elt->val;
}
}
    在进行比较的时候,上面的代码采取了一定的变通。正常情况下,将需要查询的键值与查询范围内的每一个字符串键值进行比较的时候可以调用strcmp实现,对于Apache而言则就是strcasecmp。为了能够加快查找的速度,Apache中对于每一个字符串,取其前面的4个字符计算该字符串的校验码:
#define COMPUTE_KEY_CHECKSUM(key, checksum)    \
{                                              \
    const char *k = (key);                     \
    apr_uint32_t c = (apr_uint32_t)*k;         \

    (checksum) = c;                            \
    (checksum) <<= 8;                          \
    if (c) {                                   \
        c = (apr_uint32_t)*++k;                \
        checksum = c;                         \
    }                                          \
    (checksum) <<= 8;                          \
    if (c) {                                   \
        c = (apr_uint32_t)*++k;                \
        checksum = c;                         \
    }                                          \
    (checksum) <<= 8;                          \
    if (c) {                                   \
        c = (apr_uint32_t)*++k;                \

        checksum = c;                         \
    }                                          \
    checksum &= CASE_MASK;                     \
}
    宏COMPUTE_KEY_CHECKSUM计算给定key的校验码checksum,因此对于任何的字符串比较都会分为两个步骤:
    checksum == next_elt->key_checksum) &&!strcasecmp(next_elt->key, key
    首先比较它们的校验码,即前四个字符,假如相等,才会进一步调用strcasecmp进行比较;假如校验整数值不相等,那么就没有必要调用strcasecmp进一步比较。由于整数之间的比较速度比较快,因此通过这种两阶段比较能够有效的提高比较速度。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感爱好的朋友可以通过flydish1234 at sina.com.cn与之联系!

假如你觉得本文不错,请点击文后的“推荐本文”链接!!

上一篇:好的测试工程师应具备的素质 人气:212
下一篇:XMI与UML合力推动产品开发(1) 人气:197
浏览全部软件工程的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-7-25 WikyBlog v1.7.0.1 多国语言版
2008-7-25 乐彼网上开店系统(56770 Eshop)
2008-7-25 赛特网站管理系统sitecms v3.6.0
2008-7-25 Modoer多功能点评系统 v1.0.1 Bu
2008-7-25 Shangducms Teamsuit! v1.1.0 开
2008-7-25 幻影动漫网视频系统(Ppdong) v1.
2008-7-25 acteecompany企业网站建设系统 v
2008-7-25 恒浪整合管理系统 ims v4.1 ACCE
2008-7-25 艺术图库系统 v1.0 beta
2008-7-19 UltraEdit 简体中文增强版 14.10
2008-7-19 CentOS 5.2 i386 LiveCD
2008-7-19 Snapture多功能相机 v1.4
2008-7-19 iAcces中文输入法 v1.0Build016
2008-7-19 Cookbook烹饪秘籍 v2.5
2008-7-19 苹果专用DVD转换工具 v1.1.59汉化
2008-7-19 Modem修复软件ZiPhone修改版04.0
2008-7-19 AgileMessenger即时通讯工具美化
2008-7-19 Sketches画图软件 v0.7b6破解版


  发表评论
姓 名: 验证码:
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号