思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx

上传人:b****4 文档编号:16593164 上传时间:2022-11-24 格式:DOCX 页数:13 大小:138.98KB
下载 相关 举报
思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx_第1页
第1页 / 共13页
思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx_第2页
第2页 / 共13页
思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx_第3页
第3页 / 共13页
思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx_第4页
第4页 / 共13页
思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx

《思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx》由会员分享,可在线阅读,更多相关《思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx(13页珍藏版)》请在冰豆网上搜索。

思考mysql内核之初级系列9innodb动态数组的实现Word下载.docx

/*MTR_ACTIVE,MTR_COMMITTING,MTR_COMMITTED*/

dyn_array_tmemo;

/*memostackforlocksetc.*/

dyn_array_tlog;

/*mini-transactionlog*/

iboolmodifications;

/*TRUEifthemtrmademodificationsto

bufferpoolpages*/

ulintn_log_recs;

/*countofhowmanypageinitiallogrecords

havebeenwrittentothemtrlog*/

ulintlog_mode;

/*specifieswhichoperationsshouldbe

logged;

defaultvalueMTR_LOG_ALL*/

dulintstart_lsn;

/*startlsnofthepossiblelogentryfor

thismtr*/

dulintend_lsn;

/*endlsnofthepossiblelogentryfor

ulintmagic_n;

};

我们将要开始fsp0fsp.c的内容,为了便于内容的独立,会将mtr的内容先剥离,在讲完存储之后,会继续讲B树,然后会到事务。

Bingxi:

“alex,我赞同这一点。

不过我认为还是把该结构体中的一个常用算法讲下,就是动态数组,mtr_t结构体中会有两个这样的结构成员:

dyn_array_tmemo;

dyn_array_tlog;

所谓动态数组,就是一个动态的虚拟线性数组,数组的基本元素是byte,主要用于存放mtr的锁信息以及log。

如果对于一个block数组不够存放时,需要增加新的block,每个block对应的存放数据字段的长度是固定的(默认值是512),但是不一定会用完。

假设已经用了500个字节,这时候需要继续存放18个字节的内容,就会在该块中存放不了,会产生一个新的block用于存放。

从而前一个block使用值为500。

我们先看了结构体的定义:

typedefstructdyn_block_structdyn_block_t;

typedefdyn_block_tdyn_array_t;

……

/*#################################################################*/

/*NOTE!

Donotusethefieldsofthestructdirectly:

thedefinition

appearshereonlyforthecompilertoknowitssize!

*/

structdyn_block_struct{

mem_heap_t*heap;

/*inthefirstblockthisis!

=NULL

ifdynamicallocationhasbeenneeded*/

ulintused;

/*numberofdatabytesusedinthisblock*/

bytedata[DYN_ARRAY_DATA_SIZE];

/*storageforarrayelements*/

UT_LIST_BASE_NODE_T(dyn_block_t)base;

/*linearlistofdynblocks:

thisnodeis

usedonlyinthefirstblock*/

UT_LIST_NODE_T(dyn_block_t)list;

/*linearlistnode:

usedinallblocks*/

#ifdefUNIV_DEBUG

ulintbuf_end;

/*onlyinthedebugversion:

ifdynarrayis

opened,thisisthebufferendoffset,else

thisis0*/

#endif

在这个结构体中,我们可以看到上一篇聊到的list结构,可以通过list查找prev、next。

Alex,这里面就带来了一些问题:

1)dyn_array_t与dyn_block_t是同样的定义,而一个动态数组只有一个首结点,那么UT_LIST_BASE_NODE_T(dyn_block_t)base成员是不是每个结构体都是有效的,2)一开始分配的时候只分配了一个结构体,也就是512字节的大小,如果不够用,则扩展了一个,插入到链表里面,链表成员是1个还是2个?

3)使用的时候,如何判断一个block已经使用满了,比如前面我们说到一个情况:

500个字节剩下了12个不够18个时候,产生了一个新的block,假设这时候要使用其中的10个字节,两个block都是符合,用哪个?

如果用后一个,怎么标识前一个是满的。

“你的问题太多了,呵呵。

我们先放下问题,看一下动态数组的初始化过程。

这里面,我们还需要主意一点。

虽然数据结构用的是同一个dyn_block_struct,但是我们称第一个节点为arr,表明这个是动态数据的头节点。

其它的节点,我们称为block节点。

现在开始进行debug,在mtr0mtr.ic文件中的mtr_start函数体内设置断点,这里也是动态数组创建的唯一入口,设置断点进行调试。

/*******************************************************************

Startsamini-transactionandcreatesamini-transactionhandle

andabufferinthememorybuffergivenbythecaller.*/

mtr_t*

mtr_start(

/*======*/

mtrbufferwhichalsoactsas

themtrhandle*/

memorybufferforthemtrbuffer*/

{

//会创建两个动态数组,在两个创建的任一个设置断点

dyn_array_create(&

(mtr->

memo));

log));

mtr->

log_mode=MTR_LOG_ALL;

modifications=FALSE;

n_log_recs=0;

state=MTR_ACTIVE;

magic_n=MTR_MAGIC_N;

return(mtr);

}

点击F11进入函数,查看动态数据的创建过程:

/*************************************************************************

Initializesadynamicarray.*/

dyn_array_t*

dyn_array_create(

/*=============*/

initializeddynarray*/

dyn_array_t*arr)/*in:

pointertoamemorybufferof

sizesizeof(dyn_array_t)*/

ut_ad(arr);

ut_ad(DYN_ARRAY_DATA_SIZE<

DYN_BLOCK_FULL_FLAG);

arr->

heap=NULL;

used=0;

buf_end=0;

magic_n=DYN_BLOCK_MAGIC_N;

return(arr);

}

执行该函数之后,结构体的情况见图1:

创建完成之后,我们就可以使用该动态数组了。

作为例子,我们在mtr_memo_push函数体内设置断点。

/*******************************************************

Pushesanobjecttoanmtrmemostack.*/

void

mtr_memo_push(

/*==========*/

mtr_t*mtr,/*in:

void*object,/*in:

object*/

ulinttype)/*in:

objecttype:

MTR_MEMO_S_LOCK,...*/

dyn_array_t*memo;

mtr_memo_slot_t*slot;

ut_ad(object);

ut_ad(type>

=MTR_MEMO_PAGE_S_FIX);

ut_ad(type<

=MTR_MEMO_X_LOCK);

ut_ad(mtr);

ut_ad(mtr->

magic_n==MTR_MAGIC_N);

memo=&

memo);

//从动态中分配大小为sizeof(mtr_memo_slot_t)的空间

//然后对获取的空间进行赋值

slot=dyn_array_push(memo,sizeof(mtr_memo_slot_t));

slot->

object=object;

type=type;

从中我们可以得知dyn_array_pus是分配空间的地方(dyn_array_open函数有这样的功能,本文后面会提到),我们按F11进入该函数体。

Makesroomontopofadynarrayandreturnsapointertotheaddedelement.

Thecallermustcopytheelementtothepointerreturned.*/

void*

dyn_array_push(

/*===========*/

pointertotheelement*/

dyn_array_t*arr,/*in:

dynamicarray*/

ulintsize)/*in:

sizeinbytesoftheelement*/

dyn_block_t*block;

ut_ad(arr->

magic_n==DYN_BLOCK_MAGIC_N);

ut_ad(size<

=DYN_ARRAY_DATA_SIZE);

ut_ad(size);

//步骤1:

取得使用的used

//存在多个节点是,arr表示的是链表中的首节点

block=arr;

used=block->

used;

//步骤2:

如果首结点block有足够的空间存储,则返回指针,并修改used值。

这种情况只出现在:

该动态数组只有一个节点。

//used+size<

=DYN_ARRAY_DATA_SIZE表示有足够的空间存储

if(used+size>

DYN_ARRAY_DATA_SIZE){

/*Getthelastarrayblock*/

//步骤3:

首结点没有空间存储,则取得base列表的最后一个结点

//该函数等价于:

block=UT_LIST_GET_LAST(arr->

base);

//如果有多个节点,首先肯定不符合used+size<

=DYN_ARRAY_DATA_SIZE,在后文中有描述。

block=dyn_array_get_last_block(arr);

//步骤4:

如果最后一个结点有足够空间,则分配

//否则增加一个新的block

block=dyn_array_add_block(arr);

}

block->

used=used+size;

ut_ad(block->

used<

return((block->

data)+used);

该函数的功能就是进行分配空间,如果有足够的空间则分配,否则就调用函数dyn_array_add_block生成一个新的block。

假象现在的情形是一个block扩展为两个block的情况。

查看该函数的实现。

/****************************************************************

Addsanewblocktoadynarray.*/

dyn_block_t*

dyn_array_add_block(

/*================*/

createdblock*/

dynarray*/

结点是1扩展为2,还是n扩展为n+1(n>

=2)

//arr->

heap=NULL则是1扩展为2,将自己作为首结点放在链表上,并分配一个内存堆

if(arr->

heap==NULL){

UT_LIST_INIT(arr->

UT_LIST_ADD_FIRST(list,arr->

base,arr);

//1扩展为2的时候,创建一个heap,n扩展n+1(n>

=2)时,则使用该heap

heap=mem_heap_create(sizeof(dyn_block_t));

}

取得最后一个结点,将该block的used字段进行DYN_BLOCK_FULL_FLAG与操作,表示该结点已经使用满。

每增加一个新的block总要将前一个block设置为已满,因此只有最后一个block是可用的。

即使如前文所例,500字节不够用时创建了一个新的block,第二次有申请10个字节时,显示显示该块的大小>

512了,因为DYN_BLOCK_FULL_FLAG的值为:

0x1000000UL

used=block->

used|DYN_BLOCK_FULL_FLAG;

heap=arr->

heap;

创建一个新结点,并插入到链表尾

block=mem_heap_alloc(heap,sizeof(dyn_block_t));

UT_LIST_ADD_LAST(list,arr->

base,block);

return(block);

1个结点扩展为2个结点后,见图2(prev和next指向结构的首字节,便于绘图进行了简化,此处加以说明。

list的prev和next参考前一篇文章):

2个结点扩展为3个结点,见图3:

到这里,我们就解决了前面的三个问题。

问题1:

dyn_array_t与dyn_block_t是同样的定义,而一个动态数组只有一个首结点,那么UT_LIST_BASE_NODE_T(dyn_block_t)base成员是不是每个结构体都是有效的?

“这个问题我明白,只有首结点的base是有效的。

从图1中可以看出,只有一个结点时,base是无效。

图2中,arr的base有两个成员,首结点是第一个成员,新增加的结点在首结点的后面。

图3中,arr的base有三个成员,新增的成员在链表尾。

“问题2:

一开始分配的时候只分配了一个结构体,也就是512字节的大小,如果不够用,则扩展了一个,插入到链表里面,链表成员是1个还是2个?

“从1个扩展到2个,链表的成员是2。

“问题3:

使用的时候,如何判断一个block已经使用满了,比如前面我们说到一个情况:

“始终只有最后一个结点可能被使用,只有一个成员时,本身就是最后一个结点。

新增结点时,会将前一个结点设置为已满。

设置方法如下:

block->

这样进行分配操作时候,used+size>

DYN_ARRAY_DATA_SIZE这个条件一定为真。

表示首结点已经用满了,然后取最后一个结点。

该条件只有一种情况为否,就是动态数组只有一个成员。

if(used+size>

“good,我现在问第4个问题:

我们需要插入三个元素,我们插入一个元素,就需要修改一次used,再插入,又得调用push函数进行操作。

频繁的对dyn的数据结构进行操作。

这样的效率是很低的。

“稍等,我看下代码。

找到了,通过dyn_array_open、dyn_array_close函数可以解决这个问题。

这两个函数建议大家看下。

另外,我也问你第5个问题,是不是大于512字节的数据就不能插入?

“这个问题,请参考函数dyn_push_string。

其它的函数也看一下,养成看函数的习惯,呵呵。

今天就到这儿吧。

“ok”

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1