DedeCMS自定义模型使用教程
2012-12-04 14:36
537 查看
HASH是NGINX核心数据结构之一.见几个链接.分析的很详细
1.http://www.linuxidc.com/Linux/2012-08/67040.htm
2.http://www.oschina.net/question/234345_42065
3.http://blog.csdn.net/lifeibo/article/details/5897126
4.http://code.google.com/p/nginxsrp/wiki/NginxCodeReview
//ngx_hash_key_t中的key即为ngx_hash_elt中的name(name余下的部分跟在name[1]后), +2是加上len的大小,然后据*value对齐
#define NGX_HASH_ELT_SIZE(name) \
(sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
ngx_int_t
ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
{
u_char *elts;
size_t len;
u_short *test;
ngx_uint_t i, n, key, size, start, bucket_size;
ngx_hash_elt_t *elt, **buckets;
for (n = 0; n < nelts; n++) {
//一个桶至少容得下一个ngx_hash_elt, +sizeof(void *)是因为一个桶(bucket)是以void *标识结尾的.
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names
) + sizeof(void *))
{
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build the %s, you should "
"increase %s_bucket_size: %i",
hinit->name, hinit->name, hinit->bucket_size);
return NGX_ERROR;
}
}
//test是用来测试冲突是否频繁,至于为什么乘以sizeof(u_short),见下面的 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
//即一个bucket至多为u_short大,拟max_size * sizeof(u_short)即可容纳max_size个bucket,不会内存不够
//test中的每个元素只是存储一个bucket占多大内存,而不是分配这么多内存.test只是用来测试的
test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
if (test == NULL) {
return NGX_ERROR;
}
bucket_size = hinit->bucket_size - sizeof(void *);//减去bucket最后标识结尾的void*
start = nelts / (bucket_size / (2 * sizeof(void *)));//(2 * sizeof(void *))是ngx_hash_elt的最小内存占用. 即len 和name 加起来最多是4字节,和*value对齐
start = start ? start : 1;
//这段没看懂
if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
start = hinit->max_size - 1000;
}
for (size = start; size < hinit->max_size; size++) {
ngx_memzero(test, size * sizeof(u_short));//注意这里每次都重置前面填充的内存
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
//计算是否能容下所有ngx_hash_elt
key = names
.key_hash % size;//当size==1时,key 一直是0
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
#if 0
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: %ui %ui \"%V\"",
size, key, test[key], &names
.key);
#endif
if (test[key] > (u_short) bucket_size) {
goto next;
}
}
goto found;
next:
continue;
}
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build the %s, you should increase "
"either %s_max_size: %i or %s_bucket_size: %i",
hinit->name, hinit->name, hinit->max_size,
hinit->name, hinit->bucket_size);
ngx_free(test);
return NGX_ERROR;
found:
//重置test,注意这里初始化为一个void*的大小,正好是一个bucket的结尾void*
for (i = 0; i < size; i++) {
test[i] = sizeof(void *);
}
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
key = names
.key_hash % size;
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
}
len = 0;
//以ngx_cacheline_size对齐,并计算所有元素总大小
ngx_cacheline_size = 32;
for (i = 0; i < size; i++) {
if (test[i] == sizeof(void *)) {
continue;
}
test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));
len += test[i];
}
if (hinit->hash == NULL) {//如果没有初始化过hash
//初始化hash结构会申请ngx_hash_wildcard_t的空间(看hash结构图)
hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
+ size * sizeof(ngx_hash_elt_t *));
if (hinit->hash == NULL) {
ngx_free(test);
return NGX_ERROR;
}
buckets = (ngx_hash_elt_t **)
((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));
} else {
buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
if (buckets == NULL) {
ngx_free(test);
return NGX_ERROR;
}
}
elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
if (elts == NULL) {
ngx_free(test);
return NGX_ERROR;
}
elts = ngx_align_ptr(elts, ngx_cacheline_size);
//计算每个bucket的起始位置
for (i = 0; i < size; i++) {
if (test[i] == sizeof(void *)) {
continue;
}
buckets[i] = (ngx_hash_elt_t *) elts;
elts += test[i];
}
for (i = 0; i < size; i++) {
test[i] = 0;
}
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
key = names
.key_hash % size;
elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
elt->value = names
.value;
elt->len = (u_short) names
.key.len;
ngx_strlow(elt->name, names
.key.data, names
.key.len);
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
}
for (i = 0; i < size; i++) {
if (buckets[i] == NULL) {
continue;
}
elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);
elt->value = NULL;
}
ngx_free(test);
hinit->hash->buckets = buckets;
hinit->hash->size = size;
#if 0
for (i = 0; i < size; i++) {
ngx_str_t val;
ngx_uint_t key;
elt = buckets[i];
if (elt == NULL) {
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: NULL", i);
continue;
}
while (elt->value) {
val.len = elt->len;
val.data = &elt->name[0];
key = hinit->key(val.data, val.len);
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: %p \"%V\" %ui", i, elt, &val, key);
elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
sizeof(void *));
}
}
#endif
return NGX_OK;
}
1.http://www.linuxidc.com/Linux/2012-08/67040.htm
2.http://www.oschina.net/question/234345_42065
3.http://blog.csdn.net/lifeibo/article/details/5897126
4.http://code.google.com/p/nginxsrp/wiki/NginxCodeReview
//ngx_hash_key_t中的key即为ngx_hash_elt中的name(name余下的部分跟在name[1]后), +2是加上len的大小,然后据*value对齐
#define NGX_HASH_ELT_SIZE(name) \
(sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
ngx_int_t
ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
{
u_char *elts;
size_t len;
u_short *test;
ngx_uint_t i, n, key, size, start, bucket_size;
ngx_hash_elt_t *elt, **buckets;
for (n = 0; n < nelts; n++) {
//一个桶至少容得下一个ngx_hash_elt, +sizeof(void *)是因为一个桶(bucket)是以void *标识结尾的.
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names
) + sizeof(void *))
{
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build the %s, you should "
"increase %s_bucket_size: %i",
hinit->name, hinit->name, hinit->bucket_size);
return NGX_ERROR;
}
}
//test是用来测试冲突是否频繁,至于为什么乘以sizeof(u_short),见下面的 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
//即一个bucket至多为u_short大,拟max_size * sizeof(u_short)即可容纳max_size个bucket,不会内存不够
//test中的每个元素只是存储一个bucket占多大内存,而不是分配这么多内存.test只是用来测试的
test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
if (test == NULL) {
return NGX_ERROR;
}
bucket_size = hinit->bucket_size - sizeof(void *);//减去bucket最后标识结尾的void*
start = nelts / (bucket_size / (2 * sizeof(void *)));//(2 * sizeof(void *))是ngx_hash_elt的最小内存占用. 即len 和name 加起来最多是4字节,和*value对齐
start = start ? start : 1;
//这段没看懂
if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
start = hinit->max_size - 1000;
}
for (size = start; size < hinit->max_size; size++) {
ngx_memzero(test, size * sizeof(u_short));//注意这里每次都重置前面填充的内存
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
//计算是否能容下所有ngx_hash_elt
key = names
.key_hash % size;//当size==1时,key 一直是0
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
#if 0
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: %ui %ui \"%V\"",
size, key, test[key], &names
.key);
#endif
if (test[key] > (u_short) bucket_size) {
goto next;
}
}
goto found;
next:
continue;
}
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build the %s, you should increase "
"either %s_max_size: %i or %s_bucket_size: %i",
hinit->name, hinit->name, hinit->max_size,
hinit->name, hinit->bucket_size);
ngx_free(test);
return NGX_ERROR;
found:
//重置test,注意这里初始化为一个void*的大小,正好是一个bucket的结尾void*
for (i = 0; i < size; i++) {
test[i] = sizeof(void *);
}
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
key = names
.key_hash % size;
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
}
len = 0;
//以ngx_cacheline_size对齐,并计算所有元素总大小
ngx_cacheline_size = 32;
for (i = 0; i < size; i++) {
if (test[i] == sizeof(void *)) {
continue;
}
test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));
len += test[i];
}
if (hinit->hash == NULL) {//如果没有初始化过hash
//初始化hash结构会申请ngx_hash_wildcard_t的空间(看hash结构图)
hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
+ size * sizeof(ngx_hash_elt_t *));
if (hinit->hash == NULL) {
ngx_free(test);
return NGX_ERROR;
}
buckets = (ngx_hash_elt_t **)
((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));
} else {
buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
if (buckets == NULL) {
ngx_free(test);
return NGX_ERROR;
}
}
elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
if (elts == NULL) {
ngx_free(test);
return NGX_ERROR;
}
elts = ngx_align_ptr(elts, ngx_cacheline_size);
//计算每个bucket的起始位置
for (i = 0; i < size; i++) {
if (test[i] == sizeof(void *)) {
continue;
}
buckets[i] = (ngx_hash_elt_t *) elts;
elts += test[i];
}
for (i = 0; i < size; i++) {
test[i] = 0;
}
for (n = 0; n < nelts; n++) {
if (names
.key.data == NULL) {
continue;
}
key = names
.key_hash % size;
elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
elt->value = names
.value;
elt->len = (u_short) names
.key.len;
ngx_strlow(elt->name, names
.key.data, names
.key.len);
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names
));
}
for (i = 0; i < size; i++) {
if (buckets[i] == NULL) {
continue;
}
elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);
elt->value = NULL;
}
ngx_free(test);
hinit->hash->buckets = buckets;
hinit->hash->size = size;
#if 0
for (i = 0; i < size; i++) {
ngx_str_t val;
ngx_uint_t key;
elt = buckets[i];
if (elt == NULL) {
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: NULL", i);
continue;
}
while (elt->value) {
val.len = elt->len;
val.data = &elt->name[0];
key = hinit->key(val.data, val.len);
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: %p \"%V\" %ui", i, elt, &val, key);
elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
sizeof(void *));
}
}
#endif
return NGX_OK;
}
相关文章推荐
- Zend Framework教程之模型Model基本规则和使用方法
- CSS3中几个新增加的盒模型属性使用教程
- Libgdx New 3D API 教程之 -- 使用Libgdx加载模型
- WOW模型导出到Unity3D使用教程
- 使用Weka进行数据挖掘(Weka教程九)模型序列化/持久化存储和加载
- OpenGL教程翻译 第二十二课 使用Assimp加载模型
- Java的Jackson库的使用及其树模型的入门学习教程
- 使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型
- PowerDesigner 业务处理模型( BPM ) 说明 及Enterprise Architect使用教程
- [转]一步步使用3Dmax+Photoshop为游戏关卡设计瓦片化3D模型和无缝贴图(视频教程)
- 自定义模型使用教程
- MXNet官方文档教程(4):使用预训练好的模型
- dedecms二次开发:自定义模型使用教程
- ASP.NET MVC Music Store教程(6):使用数据注释为模型进行验证
- MXNet官方文档中文版教程(8):使用预训练模型预测
- OpenGL ES 学习教程(六) 使用开源库 Assimp 将 Obj 模型 转换成自己的格式
- 使用ASP.NET WEB API构建基于REST风格的服务实战系列教程(一)——使用EF6构建数据库及模型
- 使用Weka进行数据挖掘(Weka教程七)Weka分类/预测模型构建与评价
- Zend Framework教程之模型Model基本规则和使用方法
- PowerDesigner使用教程 —— 概念数据模型(CDM模型)