Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1256280
  • 博文数量: 185
  • 博客积分: 495
  • 博客等级: 下士
  • 技术积分: 1418
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-02 15:12
个人简介

治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu

文章分类

全部博文(185)

文章存档

2019年(1)

2018年(12)

2017年(5)

2016年(23)

2015年(1)

2014年(22)

2013年(82)

2012年(39)

分类:

2018-08-28 15:29:15

原文地址:ZFS磁盘格式(5) 作者:qincp-

第五章 ZAP

ZAPZFS属性处理器)是DMU之上的模块,对ZAP类型的类型的对象进行操作。ZAP独享是一种DMU对象,用于存储以name/value对表示的属性。属性的Name部分是一个以’\0’结尾的字符串,长度最长为256字节(包括’\0’)。属性的Value部分是一个整数数组,大小只受限于ZAP数据块的大小。

ZAP对象用于存储数据集的属性,文件系统对象导航,存储pool属性等。下标列出ZAP对象的类型。

13      ZAP对象类型

ZAP Object Type

DMU_OT_OBJECT_DIRECTORY

DMU_OT_DSL_DIR_CHILD_MAP

DMU_OT_DSL_DS_SNAP_MAP

DMU_OT_DSL_PROPS

DMU_OT_DIRECTORY_CONTENTS

DMU_OT_MASTER_NODE

DMU_OT_DELETE_QUEUE

DMU_OT_ZVOL_PROP

ZAP对象有两种形式:微ZAP对象和肥ZAP对象。微ZAP对象是肥ZAP对象的轻量版本,包含小量的属性,提供一个简单和快速查找机制。而肥ZAP对象类型比较适合包含大量属性的ZAP对象。

ZFS使用下面几个规则来决定使用肥ZAP还是微ZAP

如果下面三个条件全部满足,则使用微ZAP

1.            所有name/value对可以放入一个块。ZFS最大数据块大小为128K,这样大小的块可以放2047ZAP条目。

2.            所有属性的值是uint64_t类型。

3.            每个属性的名称的长度小于或者等于50个字符(包含‘\0’)

如果其中之一不满足,则需要使用肥ZAP

ZAP对象的每个块的前64位用于表示这个块包含的ZAP内容的类型。下表列出了这些类型。

14 ZAP对象块类型

类型

描述

ZBT_MICRO

 

块包含了微ZAP条目

(1ULL << 63) + 3

ZBT_HEADER

 

块用于肥ZAP。这个标志仅用于肥ZAP的第一个块。

(1ULL << 63) + 1

ZBT_LEAF

 

块用于肥ZAP,这个标志用于除第一个块外的其他块

(1ULL << 63) + 0

 

5.1 ZAP

ZAP为存储少量属性实现了一个简单机制。微ZAP对象由一个块组成,包含一个微ZAP条目(mzap_ent_phys_t结构)数组。每个存储在微ZAP对象中的属性由这个数组中的一个元素表示。

ZAP块以这样的方式组织:块的头128字节包含一个微ZAP头结构,mzap_phys_t。这个结构包含一个64位的ZBT_MICRO指示这个块用户存储微ZAP条目;这后面是一个64salt值,该值传入hash以使得每一个ZAP对象的hash函数都是不同的;再后面是42字节的空间保留;最后64字节包含第一个微ZAP条目(mzap_ent_phys_t类型)。块中剩下的空间存储一个mzap_ent_phys_t结构数组。下图展现了块的结构:

15 ZAP块结构

Mzap_ent_phys_t结构定义如下。

#define MZAP_ENT_LEN 64

#define MZAP_NAME_LEN (MZAP_ENT_LEN - 84 - 2)

typedef struct mzap_ent_phys {

uint64_t mze_value;

uint32_t mze_cd;

uin16_t mze_pad;

char mze_name[MZAP_NAME_LEN];

} mzap_ent_phys_t;

mze_value: 64位整数值。

mze_cd: 32比特冲突识别(“CD”):和一个条目关联,该条目的hash值和ZAP对象中另外一个条目相同。当一个条目插入ZAP对象中,被赋予了具有相同hash值的条目的没有使用的最小CD值。如果不存在hash冲突,则CD值为0

mze_pad: 填充,保留以后使用。

mze_name: ’\0’为结束符的字符串,长度不超过50字节。

5.2 ZAP

ZAP有一个灵活的架构,用于存储大量的属性,这些属性可以有长的名称和复杂的值类型。本节首先描述肥ZAP对象的基本结构,然后对对象的每一个组成部分进行详细解析。

ZAP对象中的所有条目的安排是基于属性名的64hash值的。该hash值用于在一个指针表中进行索引(如下图左边部分)。hash值中用于下标索引的位数(有时称之为前缀)取决于表中条目的数量。表中的条目数随时可能变化。当前的机制是,如果某个hash桶对应的冲突链表超过了一个块可以容纳的大小时,指针表将扩容。指针表的元素指向一个肥ZAP块链表,称为叶块,由zap_leaf_phys结构表示。每个叶块由一些chunkzap_leaf_chunks)组成,每个属性存在一个或多个chunk中。下图显示基本的肥ZAP结构,其中的组件在随后详细描述:

16 ZAP基本结构

5.2.1 zap_phys_t

ZAP对象的第一个块包含128KB大小的zap_phys_t结构,根据指针表的大小情况,指针表也可以被包含在这个结构结构中。如果指针表太大无法放进zap_phys_t,则在zap_phys_tzap_table_phys域存放了指针表的位置信息。结构定义如下:

Struct zap_phys_t{

uint64_t zap_block_type

uint64_t zap_magic

struct zap_table_phys {

uint64_t zt_blk

uint64_t zt_numblks

uint64_t zt_shift

uint64_t zt_nextblk

uint64_t zt_blk_copied

} zap_ptrtbl;

uint64_t zap_freeblk

uint64_t zap_num_leafs

uint64_t zap_num_entries

uint64_t zap_salt

uint64_t zap_pad[8181]

uint64_t zap_leafs[8192]

}

zap_block_type:

表示ZAP块类型的64位整数,第一个块始终是ZBT_HEADER类型(参见表14

zap_magic:

64位的ZAP魔数0x2F52AB2AB (zfs-zap-zap)

zap_table_phys:

描述指针表的结构。

zt_blk:

指针表的第一个块的块id。该域仅用于指针表在zap_phys_t结构外的情况下。指针表在zap_phys_t中时,该域为0

zt_numblks:

用于指针表的块数目。该域仅用于指针表在zap_phys_t结构外的情况下。指针表在zap_phys_t中时,该域为0

zt_shift:

指针表hash值前缀的位数,如果指针表在zap_phys_t中,该值为13

uint64_t zt_nextblk:

uint64_t zt_blks_copied:

这两个域在指针表尺寸变化时使用。

zap_freeblk

第一个可用于分配新的zap_leafZAP

zap_num_leafs:

包含在这个ZAP对象中的zap_leaf_phys_t结构数

zap_salt:

salt值被放入hash函数,使得每个ZAP对象的hash函数各不相同。

zap_num_entries:

存放在ZAP对象中的属性数。

zap_leafs[8192]:

这个数组包含213个指针表条目,如果指针表小于213,可以存放在这里,否则,这个域不使用。

5.2.2 指针表

指针表是一个hash表,该hash表使用链表方法来处理冲突。每个hash桶包括一个64位整数指示层0id,即冲突链表的第一个元素存储的位置。通过ZAP条目的属性名计算出一个64hash值,使用这个hash值的高几位可以得到在指针表中对应的指针位置。Hash值中使用的这高几位称为前缀,其值由zt_shift指定。

5.2.3 zap_leaf_phys_t

指针表的元素指向zap_leaf_phys_t结构。指针表的hash冲突链表由zap_leaf_phys_t保存。这个结构包含一个头,一个hash表,以及一些chunk

typedef struct zap_leaf_phys {

struct zap_leaf_header {

uint64_t lhr_block_type;

uint64_t lhr_next;

uint64_t lhr_prefix;

uint32_t lhr_magic;

uint16_t lhr_nfree;

uint16_t lhr_nentries;

uint16_t lhr_prefix_len;

uint16_t lh_freelist;

uint8_t lh_pad2[12];

} l_hdr; /* 2 24-byte chunks */

uint16_t l_hash[ZAP_LEAF_HASH_NUMENTRIES];

union zap_leaf_chunk {

struct zap_leaf_entry {

uint8_t le_type;

uint8_t le_int_size;

uint16_t le_next;

uint16_t le_name_chunk;

uint16_t le_name_length;

uint16_t le_value_chunk;

uint16_t le_value_length;

uint16_t le_cd;

uint8_t le_pad[2];

uint64_t le_hash;

} l_entry;

struct zap_leaf_array {

uint8_t la_type;

uint8_t la_array[ZAP_LEAF_ARRAY_BYTES];

uint16_t la_next;

} l_array;

struct zap_leaf_free {

uint8_t lf_type;

uint8_t lf_pad[ZAP_LEAF_ARRAY_BYTES];

uint16_t lf_next;

} l_free;

} l_chunk[ZAP_LEAF_NUMCHUNKS];

} zap_leaf_phys_t;

 

Header

ZAP叶的头存储在zap_leaf_header结构中。描述如下:

lhr_block_type: 始终为ZBT_LEAF(参见表14

lhr_next: 块链表的下一个叶块id

lhr_prefix and lhr_prefix_len: hash值的高lhr_prefixlen位等于lhr_prefixZAP存储在这个叶(或叶链表)中。Lhr_prefixlen可以等于或者小于zt_shift(小于的情况下表示多个hash桶的冲突链表引用相同的叶)。

lhr_prefixlen can be equal to or less than zt_shift (the number of bits used to

index into the pointer table) in which case multiple pointer table buckets

reference the same leaf.

lhr_magic: 叶魔数 0x2AB1EAF (zap-leaf)

lhr_nfree: 这个叶中空闲chunk数。

lhr_nentries: 这个叶中存的ZAP条目

lhr_freelist空闲chunk链表头,zap_leaf_chunk数组下标

Leaf Hash

下面的8KBzap叶的hash表。Hash表中的条目指向zap_leaf_entry类型的chunkZAP属性条目名称的Hash值的lhr_prefix_len后面的12[c1] 用于这个hash表的索引。hash表中的每一个桶包含16位整数,作为zap_leaf_chunk数组的下标。

5.2.4 zap_leaf_chunk

每一个叶包含一个chunk数组,有三种类型的chunkzap_leaf_entryzap_leaf_arrayzap_leaf_free。每个属性由一些chunk组成,其中有一个zap_leaf_entry以及几个zap_leaf_array。下图展示这些chunk的安排。各种chunk类型的细节在后面描述。

18 zap叶结构

Zap_leaf_entry:叶hash表指向这个类型的chunk。结构中包含了指向zap_leaf_array的指针,属性的名称和值存放在zap_leaf_array中。

le_type: ZAP_LEAF_ENTRY == 252

le_int_size: Size of integers in bytes for this entry.该条目的整数字节数。

le_next: hash冲突链表中的下一个zap_leaf_chunk。链表的最后条目的le_next0xffff

le_name_chunk:包含名称的前21个字符的zap_leaf_array类型的chunk标识。

le_name_length: 属性名称的长度,包括’\0’

le_value_chunk: 包含属性值的前21字节的第一个zap_leaf_array 类型chunk标识。

le_value_length: 属性值的长度(le_int_size)

le_cd: 冲突识别(CD

le_hash: 属性名的64hash值。

zap_leaf_array: zap_leaf_array类型的chunk存储ZAP属性的名称或者值。这些chunk能够组合起来提供一个对长名称和大值的支持。Zap_leaf_arrayzap_leaf_entry中的指针指向。

la_type: ZAP_LEAF_ARRAY == 251

la_array: 21字节数组包含名称或者值。整数类型的值始终按大尾格式存储,不论处理器为何种字节序。

la_next: 16位整数的zap_leaf_chunk数组下标,指向该属性的下一个zap_leaf_array类型chunk,链表的最后元素该值为0xffffCHAIN_END)。

zap_leaf_free:未使用的chunk放在空闲chunk链表中。空闲链表的头放在叶头中。

lf_type: ZAP_LEAF_FREE == 253

lf_next16位整数,指向下一个空闲chunk


 [c1]这一段需要分析一下代码

阅读(1026) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~