您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: