ZFS源代码之旅——ZAP模块分析(二)

0. 引言

上一篇文章中,我们已经了解了ZAP对象的两种类型(microzap和fatzap)是如何在磁盘上存放的。从本文开始,我们将进一步探索这两种ZAP在内存中的组织方式,它们对上层提供的接口,以及它们函数内部的实现。

本文主要介绍相对简单的microzap的实现方式。本文按照以下方式组织:

1. 首先详细描述microzap在内存中的组织方式和它在内存中定义的结构;

2. 介绍ZAP模块对上层提供的接口;

3. 介绍microzap中各个操作的具体实现。


1. microzap的内存结构

我们已经知道,microzap在磁盘上只占用一个数据块,它的属性条目(mzap_ent_phys_t)在磁盘上按照一个数组的形式保存。然而在内存中,我们为了实现属性的名字值对(name-value)的快速查找、快速插入和删除等操作,必须用一种更高效的方式进行组织。

ZFS采用了avl树(平衡二叉树)的方式组织内存中的microzap属性条目,关于avl树的介绍大家可以去查看其它相关资料,此处不再介绍。

下面的zap结构体即为ZAP对象在内存中的结构,它的定义如下:

typedef struct zap {
	objset_t *zap_objset;
	uint64_t zap_object;
	struct dmu_buf *zap_dbuf;
	krwlock_t zap_rwlock;		/* rw_init, rw_enter, rw_exit, rw_destroy #nofrish# */
	boolean_t zap_ismicro;
	int zap_normflags;
	uint64_t zap_salt;
	union {
		struct {
			zap_phys_t *zap_phys;
			kmutex_t zap_num_entries_mtx;
			int zap_block_shift;
		} zap_fat;
		struct {
			mzap_phys_t *zap_phys;		/* memory copy of disk object content #nofrish#  */
			int16_t zap_num_entries;
			int16_t zap_num_chunks;		/* number of zap chunks  #nofrish# */
			int16_t zap_alloc_next;		/* to allocate, start from this chunk, use cyclically  #nofrish# */
			avl_tree_t zap_avl;
		} zap_micro;
	} zap_u;
} zap_t;

该结构中各个字段的意义如下:

zap_object:表示该ZAP属于哪一个object set(对象集)中;

zap_object:表示该ZAP对象的对象号;

zap_dbuf:表示该ZAP对象在内存中的缓存;

zap_rwlock:读写锁;

zap_ismicro:表示该zap结构是否表示了一个microzap结构;

zap_normflags:该字段的意义还需要研究; ==toChange==

zap_salt:表示该ZAP对象加入其hash函数的参数,以使各个ZAP对象的hash函数不同;

下面是一个联合,此处我们仅介绍zap_micro结构体:

zap_phys是指向microzap在内存中的磁盘缓存的指针,它的类型是mzap_phys_t,定义如下(各字段的具体意义见上一篇文章):

typedef struct mzap_phys {
	uint64_t mz_block_type;	/* ZBT_MICRO */
	uint64_t mz_salt;
	uint64_t mz_normflags;
	uint64_t mz_pad[5];
	mzap_ent_phys_t mz_chunk[1];
	/* actually variable size depending on block size */
} mzap_phys_t;
zap_num_entries:表示该ZAP对象中存储了多少个属性的名字值对;

zap_num_chunks:表示该ZAP对象上一共可以存储多少个属性的名字值对,对于一个数据块为128KB的microzap对象,共可以存储2047个名字值对;

zap_alloc_next:下一个空闲的子块(chunk,一个chunk可存放一个名字值对)的位置;注意,microzap的空闲子块并没有通过链表链接,故zap_alloc_next实际上表示插入一个名字值对时开始搜索空闲子块的位置,该值循环查找空闲子块,即 zap_alloc_next = (zap_alloc_next + 1)% zap_num_chunks;

zap_avl:表示zap中条目在内存中生成的avl树,它是avl_tree_t类型,定义如下:

struct avl_tree {
	struct avl_node *avl_root;	/* root node in tree */
	int (*avl_compar)(const void *, const void *);
	size_t avl_offset;		/* offsetof(type, avl_link_t field) */
	unsigned long avl_numnodes;	/* number of nodes in the tree */
	size_t avl_size;		/* sizeof user type struct */
};
我们重点要关注的是avl_compar函数指针,表示该avl树中的元素进行比较操作的函数,对于microzap来说,它的比较函数定义如下:

static int
mze_compare(const void *arg1, const void *arg2)
{
	const mzap_ent_t *mze1 = arg1;
	const mzap_ent_t *mze2 = arg2;

	if (mze1->mze_hash > mze2->mze_hash)
		return (+1);
	if (mze1->mze_hash < mze2->mze_hash)
		return (-1);
	/* If two entries have same hash, then compare the cd. #nofrish# */
	if (mze1->mze_cd &g
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值