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