glusterfs文件系统是一个分布式的文件系统,但是与很多分布式文件系统不一样,它没有元数服务器,听说swift上也是应用了这个技术的。glusterfs中每个xlator的配置信息都是用dict进行管理的。dict这玩意儿,说白了就是一个hash表,是一个key/value的内存数据库。今天花了点时间慢慢研究了glusterfs中的设计,觉得还是挺有意思的。

  上篇博客介绍了glusterfs文件系统的内存池的设计,而glusterfs的内存池正应用在这项技术上。首先,glusterfsd在程序初始化时,就建立了三个池dict_pool、dict_pair_pool、dict_data_pool。接下来看看它是怎么玩这三个内存池的呢!

  1、在使用dict之前,首先是建立dict对象,这点是面向对象的思想吧。

 dict_t *
get_new_dict (void)
{
return get_new_dict_full ();
}

  glusterfs调用get_new_dict来建立一个dict对象,接下来看看get_new_dict又做了什么呢?

 dict_t *
get_new_dict_full (int size_hint)
{
dict_t *dict = mem_get0 (THIS->ctx->dict_pool); if (!dict) {
return NULL;
} dict->hash_size = size_hint;
if (size_hint == ) {
/*
* This is the only case we ever see currently. If we ever
* need to support resizing the hash table, the resize function
* will have to take into account the possibility that
* "members" is not separately allocated (i.e. don't just call
* realloc() blindly.
*/
dict->members = &dict->members_internal;
}
else {
/*
* We actually need to allocate space for size_hint *pointers*
* but we actually allocate space for one *structure*. Since
* a data_pair_t consists of five pointers, we're wasting four
* pointers' worth for N=1, and will overrun what we allocated
* for N>5. If anybody ever starts using size_hint, we'll need
* to fix this.
*/
GF_ASSERT (size_hint <=
(sizeof(data_pair_t) / sizeof(data_pair_t *)));
dict->members = mem_get0 (THIS->ctx->dict_pair_pool);
if (!dict->members) {
mem_put (dict);
return NULL;
}
} LOCK_INIT (&dict->lock); return dict;
}

  size_hint是要分配的字典的大小。当 size_hint为1时,字典内的数据将是一个链表(用链表解决HASH冲突问题)。

  接下来看看程序又将是如何向字典中添加一项数据的呢?首先还是来看看dict_t 的数据结构吧:

 struct _dict {
unsigned char is_static:;
int32_t hash_size;
int32_t count;
int32_t refcount;
data_pair_t **members;
data_pair_t *members_list;
char *extra_free;
char *extra_stdfree;
gf_lock_t lock;
data_pair_t *members_internal;
data_pair_t free_pair;
gf_boolean_t free_pair_in_use;
};

在dict_t中有一个lock子成员,每次操作dict_t对象时,首先要对它进行加锁:

int32_t
dict_add (dict_t *this, char *key, data_t *value)
{
int32_t ret; if (!this || !value) {
gf_log_callingfn ("dict", GF_LOG_WARNING,
"!this || !value for key=%s", key);
return -;
} LOCK (&this->lock); ret = _dict_set (this, key, value, ); UNLOCK (&this->lock); return ret;
}

  不得不说glusterfs的编码风格还是挺漂亮的,它把一些细节与核心点分的很清楚,代码看上去那个爽啊!!看上面的代码:打日志与加锁放一在一块,核心的处理将在_dict_set中处理。

 static int32_t
_dict_set (dict_t *this, char *key, data_t *value, gf_boolean_t replace)
{
int hashval;
data_pair_t *pair;
char key_free = ;
int tmp = ;
int ret = ; if (!key) {
ret = gf_asprintf (&key, "ref:%p", value);
if (- == ret) {
gf_log ("dict", GF_LOG_WARNING, "asprintf failed %s", key);
return -;
}
key_free = ;
} tmp = SuperFastHash (key, strlen (key));
hashval = (tmp % this->hash_size); /* Search for a existing key if 'replace' is asked for */
if (replace) {
pair = _dict_lookup (this, key); if (pair) {
data_t *unref_data = pair->value;
pair->value = data_ref (value);
data_unref (unref_data);
if (key_free)
GF_FREE (key);
/* Indicates duplicate key */
return ;
}
} if (this->free_pair_in_use) {
pair = mem_get0 (THIS->ctx->dict_pair_pool);
if (!pair) {
if (key_free)
GF_FREE (key);
return -;
}
}
else {
pair = &this->free_pair;
this->free_pair_in_use = _gf_true;
} if (key_free) {
/* It's ours. Use it. */
pair->key = key;
key_free = ;
}
else {
pair->key = (char *) GF_CALLOC (, strlen (key) + ,
gf_common_mt_char);
if (!pair->key) {
if (pair == &this->free_pair) {
this->free_pair_in_use = _gf_false;
}
else {
mem_put (pair);
}
return -;
}
strcpy (pair->key, key);
}
pair->value = data_ref (value); pair->hash_next = this->members[hashval];
this->members[hashval] = pair; pair->next = this->members_list;
pair->prev = NULL;
if (this->members_list)
this->members_list->prev = pair;
this->members_list = pair;
this->count++; if (key_free)
GF_FREE (key);
return ;
}

  19行利用HASH算法计算HASH值,20行缩小HASH值的范围,23行到了35行为替换处理。37-48行是让我最难受的代码,这个地方不知道是不是设计的问题。55行之后是插入新的HASH键值的操作。

  再看看查询的操作吧。

 data_t *
dict_get (dict_t *this, char *key)
{
data_pair_t *pair; if (!this || !key) {
gf_log_callingfn ("dict", GF_LOG_INFO,
"!this || key=%s", (key) ? key : "()");
return NULL;
} LOCK (&this->lock); pair = _dict_lookup (this, key); UNLOCK (&this->lock); if (pair)
return pair->value; return NULL;
}

同样是先处理锁之类的杂项操作,_dict_lookup才是真正的始作俑者。

 static data_pair_t *
_dict_lookup (dict_t *this, char *key)
{
if (!this || !key) {
gf_log_callingfn ("dict", GF_LOG_WARNING,
"!this || !key (%s)", key);
return NULL;
} int hashval = SuperFastHash (key, strlen (key)) % this->hash_size;
data_pair_t *pair; for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) {
if (pair->key && !strcmp (pair->key, key))
return pair;
} return NULL;
}

  查询的代码相当的简单吧,计算一个哈希值,再查询一个链表就OK了。

  查看了glusterfs中的所有代码,glusterfs_new_dict_full调用时几乎都是传入参数1,只有dict_copy接口比较特别:

 dict_t *
dict_copy (dict_t *dict,
dict_t *new)
{
if (!dict) {
gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL");
return NULL;
} if (!new)
new = get_new_dict_full (dict->hash_size); dict_foreach (dict, _copy, new); return new;
}

从代码上看,只有此处才发挥了HASH表的作用,其它的都只是把dict_t当成链表来使用。而且这个地方也并不是用HASH表的思想,只是把一个链表转换成了HASH表。这个是我在glusterfs中见到的一处最不明智的地方。

glusterfs 中的字典查询的更多相关文章

  1. SQL Server中Table字典数据的查询SQL示例代码

    SQL Server中Table字典数据的查询SQL示例代码 前言 在数据库系统原理与设计(第3版)教科书中这样写道: 数据库包含4类数据: 1.用户数据 2.元数据 3.索引 4.应用元数据 其中, ...

  2. 13.python中的字典

    字典其实和之前的元祖和列表功能相似,都是用来储存一系列对象的.也就是一种可变容器,或者是我所比喻的革新派的菜单. 但也不是完全相同,我在之前曾经将字典称为特殊的'序列',是字典拥有序列的部分特性,但是 ...

  3. python中的{字典}

    目录 字典--dict { } 字典是无序,可变的数据类型. 字典:用于存储数据,存储大量数据,字典要比列表快:将数据和数据之间进行关联. 定义: dic = {键:值,键:值} #每个 键值对 以逗 ...

  4. 详细讲述MySQL中的子查询操作 (来自脚本之家)

    继续做以下的前期准备工作: 新建一个测试数据库TestDB: ? 1 create database TestDB; 创建测试表table1和table2: ? 1 2 3 4 5 6 7 8 9 1 ...

  5. 在update语句中使用子查询

    在update 中的 where 子句中使用子查询: UPDATE mg_page_log as a  SET  page_num=1 WHERE id in( SELECT id  from mg_ ...

  6. (九)WebGIS中的矢量查询(针对AGS和GeoServer)

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在第七章里我们知道了WebGIS中要素的本质是UICompo ...

  7. mysql中的模糊查询

    转载自:http://www.letuknowit.com/archives/90/ MySQL中实现模糊查询有2种方式:一是用LIKE/NOT LIKE,二是用REGEXP/NOT REGEXP(或 ...

  8. Hibernate中的HQL查询与缓存机制

    HQL:完全面向对象查询 SQL的执行顺序: 1.From 2.Where 过滤基础数据 where与having的区别:1.顺序不同 2.where过滤基础数据 3. 过滤聚合函数 3.Group ...

  9. 浅谈T-SQL中的子查询

    引言 这篇文章我们来简单的谈一下子查询的相关知识.子查询可以分为独立子查询和相关子查询.独立子查询不依赖于它所属的外部查询,而相关子查询则依赖于它所属的外部查询.子查询返回的值可以是标量(单值).多值 ...

随机推荐

  1. I had lots of shrapnel in my leg

    People were running up to us, and screaming and hitting us, and throwing stones and eggs. "They ...

  2. AppCode 2016.2.3 发布,支持 Swift3 的特性

    AppCode 2016.2.3 (build 162.2380.5)发布了,AppCode 是一个全新的 Objective-C.Swift 的集成开发环境,用于帮助开发 Mac.iPhone 和 ...

  3. iis express 局域网访问

    查找到配置文件添加一条绑定局域网可访问的IP地址即可: 事例: <site name="Join.Lims.Mob(11)" id="19"> &l ...

  4. Cardinal样条曲线的Javascript实现(代码篇)

    由上一篇文章得到了Cardinal曲线的矩阵表达式,下面就这个矩阵表达式就可以来对曲线进行插值了. 这里选用了JS来实现,完全是因为之前交作业的时候还不知道怎么在Xcode里建完整的C++OpenGL ...

  5. Question Of Rabbit

    题目描述 f(n) = GCD(1, n) + GCD(2, n) + GCD(3, n) + ~ ~ ~ + GCD(n - 1, n). 输入 每行一个整数N (1 < N < 400 ...

  6. IT之梦

    生活原本不孤单,可惜人们总爱感叹 日子其实很简单,而我却不甘平淡 工作中我尽情的挥洒热汗,只为让成功离自己更近一点 生活中我为人和善,只为人生的路上多一个伙伴 时间不等人,IT尚遥远 我愿舍身敬业,誓 ...

  7. asp.net页面事件执行顺序

    转自http://www.cnblogs.com/hnlyh/articles/4230388.html C#代码 using System; using System.Data; using Sys ...

  8. vimperator setting records

    vimperator confugration files :highlight Hint color:#000;background:rgb(250,230,150);border-radius:4 ...

  9. mac中使用brew安装软件,下载太慢怎么办?

    mac中使用brew安装软件,下载太慢怎么办? 本文所说的软件是指较大的软件,如果软件较小,例如软件只有几M,那么使用此方法后,提升会非常小. 了解brew原理: 1: 从网络下载安装包 2: 执行一 ...

  10. rtpMIDI Tutorial

    Tobias Erichsen private stuff & software for audio, midi and more Search Main menu Skip to prima ...