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

[经验分享] 深入理解mysql之BDB系列(3)---数据页结构(摘自老杨)

[复制链接]
发表于 2016-10-24 09:01:57 | 显示全部楼层 |阅读模式
四:数据页结构
4.1 B/H主要页结构
4.1.1结构图
http://p.blog.csdn.net/images/p_blog_csdn_net/whyangwanfu/bdb3_1210_1.bmp
4.1.2数据结构

typedef struct _db_page {
DB_LSN  lsn;  //LSN
db_pgno_t  pgno;  //页号
db_pgno_t  prev_pgno;  //前一页页号
db_pgno_t  next_pgno;  //下一页页号
db_indx_t  entries;  //items数量
db_indx_t  hf_offset; //空闲区的高地址

#define LEAFLEVEL 1
#define MAXBTREELEVEL 255
u_int8_t level;  //页层次,叶结点为1。
u_int8_t  type;  //页类型
} PAGE; //结构大小为26字节

typedef struct __pg_chksum {
u_int8_t  unused[2];  //对齐
u_int8_t  chksum[4];  //chksum
} PG_CHKSUM;

typedef struct __pg_crypto {
u_int8_t  unused[2];  //对齐
u_int8_t  chksum[DB_MAC_KEY];  //chksum
u_int8_t  iv[DB_IV_BYTES];  //iv

} PG_CRYPTO;

4.1.3相关宏功能分析

#define P_INP(dbp, pg) \
((db_indx_t *)((u_int8_t *)(pg) + SIZEOF_PAGE + \
(F_ISSET((dbp), DB_AM_ENCRYPT) ? sizeof(PG_CRYPTO) : \
(F_ISSET((dbp), DB_AM_CHKSUM) ? sizeof(PG_CHKSUM) : 0))))
功能:
取得页中index对应的首地址。

执行流程:
1.首先加上公共的页头大小,这里为SIZEOF_PAGE(26字节)
2.判断数据库是否有DB_AM_ENCRYPT标志,如果有,则加上PG_CRYPTO结构的大小。并返回。否则执行下一步。
3.判断数据库是否有DB_AM_CHKSUM标志,如果有,则加上PG_CHKSUM结构的大小。并返回。

备注:
DB_AM_ENCRYPT总是伴随DB_AM_CHKSUM标志,所以先测试DB_AM_ENCRYPT标志。


#define P_IV(dbp, pg) \
(F_ISSET((dbp), DB_AM_ENCRYPT) ? ((u_int8_t *)(pg) + \
SIZEOF_PAGE + SSZA(PG_CRYPTO, iv)) \
: NULL)
功能:
取得页中iv对应的首地址。


#define P_CHKSUM(dbp, pg) \
(F_ISSET((dbp), DB_AM_ENCRYPT) ? ((u_int8_t *)(pg) + \
SIZEOF_PAGE + SSZA(PG_CRYPTO, chksum)) :  \
(F_ISSET((dbp), DB_AM_CHKSUM) ? ((u_int8_t *)(pg) + \
SIZEOF_PAGE + SSZA(PG_CHKSUM, chksum)) \
: NULL))
功能:
取得chksum对应的首地址。


4.1.4.公共宏功能分析

#define RE_NREC(p) \
((TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO) ? PREV_PGNO(p) :\
(db_pgno_t)(TYPE(p) == P_LBTREE ? NUM_ENT(p) / 2 : NUM_ENT(p)))
#define RE_NREC_ADJ(p, adj) \
PREV_PGNO(p) += adj;
#define RE_NREC_SET(p, num) \
PREV_PGNO(p) = (num);
功能:
记录数相关操作。


#define P_INIT(pg, pg_size, n, pg_prev, pg_next, btl, pg_type) do { \
PGNO(pg) = (n); \
PREV_PGNO(pg) = (pg_prev); \
NEXT_PGNO(pg) = (pg_next); \
NUM_ENT(pg) = (0); \
HOFFSET(pg) = (db_indx_t)(pg_size); \
LEVEL(pg) = (btl); \
TYPE(pg) = (pg_type); \
} while (0)
功能:
初始化页。


#define P_OVERHEAD(dbp) P_TO_UINT16(P_INP(dbp, 0))
功能:
页头长度。

#define LOFFSET(dbp, pg) \
(P_OVERHEAD(dbp) + NUM_ENT(pg) * sizeof(db_indx_t))
功能:
空闲空间的首地址。

#define P_FREESPACE(dbp, pg) (HOFFSET(pg) - LOFFSET(dbp, pg))
功能:
空闲空间的大小。

#define P_ENTRY(dbp, pg, indx) ((u_int8_t *)pg + P_INP(dbp, pg)[indx])
功能:
取得特定索引的指针。



4.2 Q主要页结构
4.2.1数据结构

typedef struct _qpage {
DB_LSN  lsn;  //LSN
db_pgno_t  pgno;  //页号
u_int32_t  unused0[3];  //保留
u_int8_t unused1[1];  //保留
u_int8_t type;  //页类型
u_int8_t unused2[2];  //保留
u_int8_t chksum[DB_MAC_KEY];  //28-47: Checksum
u_int8_t iv[DB_IV_BYTES];  //48-63: IV
} QPAGE; //该结构大小为64字节


4.2.2相关宏功能分析

#define QPAGE_NORMAL 28
#define QPAGE_CHKSUM 48
#define QPAGE_SEC64
功能:
如果没有crypto或者checksumming,这些宏用来回收空间。


#define QPAGE_SZ(dbp) \
(F_ISSET((dbp), DB_AM_ENCRYPT) ? QPAGE_SEC : \
F_ISSET((dbp), DB_AM_CHKSUM) ? QPAGE_CHKSUM : QPAGE_NORMAL)
功能:
返回实际所需的页头大小。

执行流程:
1.如果数据库设置了DB_AM_ENCRYPT,则页头大小为64。返回。
2.如果数据库设置了DB_AM_CHKSUM,则页头大小为48。返回。
3.返回28。


4.3.overflow页结构
4.3.1相关宏功能分析

#define OV_LEN(p) (((PAGE *)p)->hf_offset)
功能:
返回页中已经存储的overflow数据。

#define OV_REF(p) (((PAGE *)p)->entries)
功能:
Overflow页被引用次数。

#define P_MAXSPACE(dbp, psize) ((psize) - P_OVERHEAD(dbp))
功能:
可以在页中存储的overflow数据的最大长度(页大小减去页头大小)。

#define P_OVFLSPACE(dbp, psize, pg) (P_MAXSPACE(dbp, psize) - HOFFSET(pg))
功能:
Overflow页中的空闲空间。



4.4.HASH页结构
4.4.1相关数据结构以及宏功能分析

#define H_KEYDATA 1  /* Key/data item. */
#define H_DUPLICATE 2  /* Duplicate key/data item. */
#define H_OFFPAGE 3  /* Overflow key/data item. */
#define H_OFFDUP  4  /* Overflow page of duplicates. */
功能:
HASH页item元组所支持的元组类型。


#define HPAGE_PTYPE(p) (*(u_int8_t *)p)
#define HPAGE_TYPE(dbp, pg, indx) (*P_ENTRY(dbp, pg, indx))
功能:
返回元组item的类型。


typedef struct _hkeydata {
u_int8_ttype;  /* 00: Page type. */
u_int8_tdata[1];  /* Variable length key/data item. */
} HKEYDATA;
#define HKEYDATA_DATA(p) (((u_int8_t *)p) + SSZA(HKEYDATA, data))
功能:
取得item中,data字段所对应的指针。


#define LEN_HITEM(dbp, pg, pgsize, indx) \
(((indx) == 0 ? (pgsize) : \
(P_INP(dbp, pg)[(indx) - 1])) - (P_INP(dbp, pg)[indx]))
功能:
取得HKEYDATA item的长度。


#define LEN_HKEYDATA(dbp, pg, psize, indx) \
(db_indx_t)(LEN_HITEM(dbp, pg, psize, indx) - HKEYDATA_SIZE(0))
功能:
取得item中data字段的长度。


#define HKEYDATA_SIZE(len) \
((len) + SSZA(HKEYDATA, data))
#define HKEYDATA_PSIZE(len) \
(HKEYDATA_SIZE(len) + sizeof(db_indx_t))
功能:
增加一个item所需要的空间。


#define PUT_HKEYDATA(pe, kd, len, type) { \
((HKEYDATA *)pe)->type = type; \
memcpy((u_int8_t *)pe + sizeof(u_int8_t), kd, len); \
}
功能:
在给定位置插入一条item元组。


#define H_NUMPAIRS(pg) (NUM_ENT(pg) / 2)
#define H_KEYINDEX(indx) (indx)
#define H_DATAINDEX(indx) ((indx) + 1)
#define H_PAIRKEY(dbp, pg, indx) P_ENTRY(dbp, pg, H_KEYINDEX(indx))
#define H_PAIRDATA(dbp, pg, indx) P_ENTRY(dbp, pg, H_DATAINDEX(indx))
#define H_PAIRSIZE(dbp, pg, psize, indx) \
(LEN_HITEM(dbp, pg, psize, H_KEYINDEX(indx)) + \
LEN_HITEM(dbp, pg, psize, H_DATAINDEX(indx)))
#define LEN_HDATA(dbp, p, psize, indx) \
LEN_HKEYDATA(dbp, p, psize, H_DATAINDEX(indx))
#define LEN_HKEY(dbp, p, psize, indx) \
LEN_HKEYDATA(dbp, p, psize, H_KEYINDEX(indx))
功能:
其他相关宏。


typedef struct _hoffpage {
u_int8_t type;  //类型以及删除标志
u_int8_t unused[3];  //保留
db_pgno_t  pgno;  //overflow页的页号
u_int32_t  tlen;  //overflow页的数量
} HOFFPAGE;
#define HOFFPAGE_PGNO(p)(((u_int8_t *)p) + SSZ(HOFFPAGE, pgno))
#define HOFFPAGE_TLEN(p) (((u_int8_t *)p) + SSZ(HOFFPAGE, tlen))
功能:
取得页号,取得长度。


#define HOFFPAGE_SIZE (sizeof(HOFFPAGE))
#define HOFFPAGE_PSIZE (HOFFPAGE_SIZE + sizeof(db_indx_t))
功能:
增加一个新元组所需要的长度。


typedef struct _hoffdup {
u_int8_t type;  //类型以及删除标志
u_int8_t unused[3];  //保留
db_pgno_t  pgno;  //overflow页的页号
} HOFFDUP;
#define HOFFDUP_PGNO(p) (((u_int8_t *)p) + SSZ(HOFFDUP, pgno))
功能:
取得页号。


#define HOFFDUP_SIZE (sizeof(HOFFDUP))
功能:
增加一个元组所需要的空间大小。



4.5.BTREE页结构

#define B_KEYDATA 1 /* Key/data item. */
#define B_DUPLICATE 2 /* Duplicate key/data item. */
#define B_OVERFLOW 3 /* Overflow key/data item. */
功能:
BTREE支持的元组类型。


typedef struct _bkeydata {
db_indx_t  len;  //元组长度
u_int8_t type;  //类型以及删除标志
u_int8_t  data[1];   //元组存放数据的地方
} BKEYDATA;
功能:
该结构对应的元组类型为B_KEYDATA。


#define GET_BKEYDATA(dbp, pg, indx) \
((BKEYDATA *)P_ENTRY(dbp, pg, indx))
功能:
取得特定的元组。


#define BKEYDATA_SIZE(len) \
(u_int16_t)DB_ALIGN((len) + SSZA(BKEYDATA, data), sizeof(u_int32_t))
#define BKEYDATA_PSIZE(len) \
(BKEYDATA_SIZE(len) + sizeof(db_indx_t))
功能:
添加一个元组,所需分配的空间大小。


typedef struct _boverflow {
db_indx_t  unused1;  //保留
u_int8_t type;  //类型以及删除标志
u_int8_t unused2;  //保留
db_pgno_t  pgno;  //页号
u_int32_t  tlen;  //页的数量。
} BOVERFLOW;
功能:
该结构对应的元组类型为B_DUPLICATE或B_OVERFLOW。


#define BOVERFLOW_SIZE \
((u_int16_t)DB_ALIGN(sizeof(BOVERFLOW), sizeof(u_int32_t)))
#define BOVERFLOW_PSIZE \
(BOVERFLOW_SIZE + sizeof(db_indx_t))

#define BITEM_SIZE(bk) \
(B_TYPE((bk)->type) != B_KEYDATA ? BOVERFLOW_SIZE : \
BKEYDATA_SIZE((bk)->len))

#define BITEM_PSIZE(bk) \
(B_TYPE((bk)->type) != B_KEYDATA ? BOVERFLOW_PSIZE : \
BKEYDATA_PSIZE((bk)->len))
功能:
增加一个元组所需要的分配空间。


4.6.BTREE中间层页结构

typedef struct _binternal {
db_indx_t len;  //元组长度
u_int8_t  type;  //类型以及删除标志
u_int8_t  unused;  //保留
db_pgno_t pgno;  //引用的页的页号
db_recno_t  nrecs;  //子树的记录数量
u_int8_t  data[1];  ///存放key */
} BINTERNAL;
功能:
内部元组结构。


#define GET_BINTERNAL(dbp, pg, indx) \
((BINTERNAL *)P_ENTRY(dbp, pg, indx))
功能:
取得特定的元组。


#define BINTERNAL_SIZE(len) \
(u_int16_t)DB_ALIGN((len) + SSZA(BINTERNAL, data), sizeof(u_int32_t))
#define BINTERNAL_PSIZE(len) \
(BINTERNAL_SIZE(len) + sizeof(db_indx_t))
功能:
增加一个元组所需分配的空间。




4.7. RECNO中间层页结构

typedef struct _rinternal {
db_pgno_t pgno;  //引用页的页号
db_recno_t  nrecs;  //子树的记录数量
} RINTERNAL;
功能:
内部元组结构。


#define GET_RINTERNAL(dbp, pg, indx) \
((RINTERNAL *)P_ENTRY(dbp, pg, indx))
功能:
取得特定的元组。


#define RINTERNAL_SIZE \
(u_int16_t)DB_ALIGN(sizeof(RINTERNAL), sizeof(u_int32_t))
#define RINTERNAL_PSIZE \
(RINTERNAL_SIZE + sizeof(db_indx_t))
功能:
增加一个元组所需分配的空间。

运维网声明 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-290501-1-1.html 上篇帖子: mysql内核分析--innodb动态数组内部实现(上) (摘自老杨) 下篇帖子: 深入理解mysql之BDB系列(2)---数据元页结构(摘自老杨)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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