设为首页 收藏本站
查看: 3198|回复: 0

[经验分享] glusterfs 中的字典查询

[复制链接]

尚未签到

发表于 2015-9-10 00:40:47 | 显示全部楼层 |阅读模式
  glusterfs文件系统是一个分布式的文件系统,但是与很多分布式文件系统不一样,它没有元数服务器,听说swift上也是应用了这个技术的。glusterfs中每个xlator的配置信息都是用dict进行管理的。dict这玩意儿,说白了就是一个hash表,是一个key/value的内存数据库。今天花了点时间慢慢研究了glusterfs中的设计,觉得还是挺有意思的。
  上篇博客介绍了glusterfs文件系统的内存池的设计,而glusterfs的内存池正应用在这项技术上。首先,glusterfsd在程序初始化时,就建立了三个池dict_pool、dict_pair_pool、dict_data_pool。接下来看看它是怎么玩这三个内存池的呢!
  1、在使用dict之前,首先是建立dict对象,这点是面向对象的思想吧。



1 dict_t *
2 get_new_dict (void)
3 {
4         return get_new_dict_full (1);
5 }

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



1 dict_t *
2 get_new_dict_full (int size_hint)
3 {
4         dict_t *dict = mem_get0 (THIS->ctx->dict_pool);
5
6         if (!dict) {
7                 return NULL;
8         }
9
10         dict->hash_size = size_hint;
11         if (size_hint == 1) {
12                 /*
13                  * This is the only case we ever see currently.  If we ever
14                  * need to support resizing the hash table, the resize function
15                  * will have to take into account the possibility that
16                  * "members" is not separately allocated (i.e. don't just call
17                  * realloc() blindly.
18                  */
19                 dict->members = &dict->members_internal;
20         }
21         else {
22                 /*
23                  * We actually need to allocate space for size_hint *pointers*
24                  * but we actually allocate space for one *structure*.  Since
25                  * a data_pair_t consists of five pointers, we're wasting four
26                  * pointers' worth for N=1, and will overrun what we allocated
27                  * for N>5.  If anybody ever starts using size_hint, we'll need
28                  * to fix this.
29                  */
30                 GF_ASSERT (size_hint <=
31                            (sizeof(data_pair_t) / sizeof(data_pair_t *)));
32                 dict->members = mem_get0 (THIS->ctx->dict_pair_pool);
33                 if (!dict->members) {
34                         mem_put (dict);
35                         return NULL;
36                 }
37         }
38
39         LOCK_INIT (&dict->lock);
40
41         return dict;
42 }
  size_hint是要分配的字典的大小。当 size_hint为1时,字典内的数据将是一个链表(用链表解决HASH冲突问题)。

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

  



1 struct _dict {
2         unsigned char   is_static:1;
3         int32_t         hash_size;
4         int32_t         count;
5         int32_t         refcount;
6         data_pair_t   **members;
7         data_pair_t    *members_list;
8         char           *extra_free;
9         char           *extra_stdfree;
10         gf_lock_t       lock;
11         data_pair_t    *members_internal;
12         data_pair_t     free_pair;
13         gf_boolean_t    free_pair_in_use;
14 };
  
  在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 -1;
}
LOCK (&this->lock);
ret = _dict_set (this, key, value, 0);
UNLOCK (&this->lock);
return ret;
}
  
  不得不说glusterfs的编码风格还是挺漂亮的,它把一些细节与核心点分的很清楚,代码看上去那个爽啊!!看上面的代码:打日志与加锁放一在一块,核心的处理将在_dict_set中处理。



1 static int32_t
2 _dict_set (dict_t *this, char *key, data_t *value, gf_boolean_t replace)
3 {
4         int hashval;
5         data_pair_t *pair;
6         char key_free = 0;
7         int tmp = 0;
8         int ret = 0;
9
10         if (!key) {
11                 ret = gf_asprintf (&key, "ref:%p", value);
12                 if (-1 == ret) {
13                         gf_log ("dict", GF_LOG_WARNING, "asprintf failed %s", key);
14                         return -1;
15                 }
16                 key_free = 1;
17         }
18
19         tmp = SuperFastHash (key, strlen (key));
20         hashval = (tmp % this->hash_size);
21
22         /* Search for a existing key if 'replace' is asked for */
23         if (replace) {
24                 pair = _dict_lookup (this, key);
25
26                 if (pair) {
27                         data_t *unref_data = pair->value;
28                         pair->value = data_ref (value);
29                         data_unref (unref_data);
30                         if (key_free)
31                                 GF_FREE (key);
32                         /* Indicates duplicate key */
33                         return 0;
34                 }
35         }
36
37         if (this->free_pair_in_use) {
38                 pair = mem_get0 (THIS->ctx->dict_pair_pool);
39                 if (!pair) {
40                         if (key_free)
41                                 GF_FREE (key);
42                         return -1;
43                 }
44         }
45         else {
46                 pair = &this->free_pair;
47                 this->free_pair_in_use = _gf_true;
48         }
49
50         if (key_free) {
51                 /* It's ours.  Use it. */
52                 pair->key = key;
53                 key_free = 0;
54         }
55         else {
56                 pair->key = (char *) GF_CALLOC (1, strlen (key) + 1,
57                                                 gf_common_mt_char);
58                 if (!pair->key) {
59                         if (pair == &this->free_pair) {
60                                 this->free_pair_in_use = _gf_false;
61                         }
62                         else {
63                                 mem_put (pair);
64                         }
65                         return -1;
66                 }
67                 strcpy (pair->key, key);
68         }
69         pair->value = data_ref (value);
70
71         pair->hash_next = this->members[hashval];
72         this->members[hashval] = pair;
73
74         pair->next = this->members_list;
75         pair->prev = NULL;
76         if (this->members_list)
77                 this->members_list->prev = pair;
78         this->members_list = pair;
79         this->count++;
80
81         if (key_free)
82                 GF_FREE (key);
83         return 0;
84 }
  19行利用HASH算法计算HASH值,20行缩小HASH值的范围,23行到了35行为替换处理。37-48行是让我最难受的代码,这个地方不知道是不是设计的问题。55行之后是插入新的HASH键值的操作。
  再看看查询的操作吧。



1 data_t *
2 dict_get (dict_t *this, char *key)
3 {
4         data_pair_t *pair;
5
6         if (!this || !key) {
7                 gf_log_callingfn ("dict", GF_LOG_INFO,
8                                   "!this || key=%s", (key) ? key : "()");
9                 return NULL;
10         }
11
12         LOCK (&this->lock);
13
14         pair = _dict_lookup (this, key);
15
16         UNLOCK (&this->lock);
17
18         if (pair)
19                 return pair->value;
20
21         return NULL;
22 }
  同样是先处理锁之类的杂项操作,_dict_lookup才是真正的始作俑者。



1 static data_pair_t *
2 _dict_lookup (dict_t *this, char *key)
3 {
4         if (!this || !key) {
5                 gf_log_callingfn ("dict", GF_LOG_WARNING,
6                                   "!this || !key (%s)", key);
7                 return NULL;
8         }
9
10         int hashval = SuperFastHash (key, strlen (key)) % this->hash_size;
11         data_pair_t *pair;
12
13         for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) {
14                 if (pair->key && !strcmp (pair->key, key))
15                         return pair;
16         }
17
18         return NULL;
19 }
  查询的代码相当的简单吧,计算一个哈希值,再查询一个链表就OK了。
  查看了glusterfs中的所有代码,glusterfs_new_dict_full调用时几乎都是传入参数1,只有dict_copy接口比较特别:



1 dict_t *
2 dict_copy (dict_t *dict,
3            dict_t *new)
4 {
5         if (!dict) {
6                 gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL");
7                 return NULL;
8         }
9
10         if (!new)
11                 new = get_new_dict_full (dict->hash_size);
12
13         dict_foreach (dict, _copy, new);
14
15         return new;
16 }
  从代码上看,只有此处才发挥了HASH表的作用,其它的都只是把dict_t当成链表来使用。而且这个地方也并不是用HASH表的思想,只是把一个链表转换成了HASH表。这个是我在glusterfs中见到的一处最不明智的地方。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-111597-1-1.html 上篇帖子: CentOS 6 部署GlusterFS 下篇帖子: 分布式文件系统GlusterFS
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表