在上一次的分析中,我们分析了验证页面是否有效的函数,向页面中添加元组项PageAddItem函数和一些其他函数的功能。接下来我们来分析其他的页面操作函数。
@H_502_2@ 下一个函数,声明:void PageRestoreTempPage(Page tempPage,Page oldPage)。这个函数的功能是:将经过特殊处理过后的临时页面tempPage拷贝回oldPage中,随后将临时页面的内存空间释放。 @H_502_2@ 接下来,定义了一个结构体,如下: @H_502_2@ typedef struct itemIdSortData{
intoffsetindex;/* linp array index */
intitemoff;/* page offset of item data */
Sizealignedlen;/* MAXALIGN(item data len) */
ItemIdDataolditemid;/* used only in PageIndexMultiDelete */
} itemIdSortData;
typedef itemIdSortData *itemIdSort; @H_502_2@ 这个结构体是用于页面中元组项排序所需要,将在随后的PageRepairFragmentation和PageIndexMultiDelete函数中用到。结构体中定义了元组项的一些参数:offsetindex:元组项位于页面linp数组中的索引,itemoff:元组项位于页面中的偏移量。alignedlen:元组项大小,最后一个参数olditemid仅用于在PageIndexMultiDelete函数当中。 @H_502_2@ 接下来是一个静态的函数:static int itemoffcompare(const void *itemidp1,const void *itemidp2),这个函数的功能很简单:它返回两个上面定义的结构体itemIdSortData的itemoff的值之差,也就是两个元组项的偏移量之差,用于后面排序的比较。 @H_502_2@ 下面的一个函数有点长,有120多行。它就是我们上面所提到的PageRepairFragmentation函数,它的声明是:void PageRepairFragmentation(Page page)。 @H_502_2@ 作用是清除页面page中的碎片。实现原理是:首先判断当前页面page是否有效,如果无效的话,报错,函数退出。接着将变量nline赋值为page中元组项的个数。接下来定义两个变量nstorage,nunused分别用于统计页面中元组项已经使用和未使用的数量值。下面便遍历页面page的所有元组项item,如果item已被使用,将nstorage增值,否则置item标志位为未使用,nunused增值。遍历完成后,如果nstorage为0的话,说明该页面page完全是空的,不需要清除碎片,只需要充值它的值便可以,否则的话建立一个itemIdSortData类型的数组,为他分配空间,用指针itemidptr来操作。遍历所有的元组项,如果元组项item已被存储,将itemidptr指向这个元组项,totallen自增元组项的长度。接下来对itemIdSortData数组按偏移量进行降序排序。接下来,遍历这个数组,这段代码为: @H_502_2@ upper = pd_special; @H_502_2@ for (i = 0,itemidptr = itemidbase; i < nstorage; i++,itemidptr++)
{
lp = PageGetItemId(page,itemidptr->offsetindex + 1);
upper -= itemidptr->alignedlen;
memmove((char *) page + upper,
(char *) page + itemidptr->itemoff,
itemidptr->alignedlen);
lp->lp_off = upper;
} @H_502_2@ upper首先被赋值为page的特殊空间起始偏移量,接下来遍历itemIdSortData类型的数组itemidbase,lP为page对应itemidptr位于原linp数组中对应索引的元组项,为什么要对offsetindex加1呢?这是因为在前面的赋值操作对原元组项的偏移量已经减1了。因为之前是对itemidbase数组按偏移量降序排序的,所以可以看到,我们这里是从页面的“后端”往前操作,每次操作一个元组项,upper减掉此元组项对应的长度。接下来调用memmove函数,将itemidbase中的元组项,移到页面中的upper位置,相当于“消除”了碎片。这个算法类似于操作系统中的存储管理中的“紧凑”操作,将分散的元组项地址连续起来,消除页面中的内部碎片。接下来便是一些收尾工作了,清除itemidbase数组的空间等操作,函数结束。从中我们可以看到:这个函数宏观上的整体过程是:统计一个页面中的“有内容”的元组项,接着把这些元组项“装入”到一个itemidbase的数组,借助这个辅助空间,移动这些元组,使得他们的页面偏移量连续起来,消除页面中的碎片,得到更多的剩余空间。 @H_502_2@ 下面的一个函数相对来说就很简单了:原型是,Size PageGetFreeSpace(Page page),这里的返回类型为“Size”, Size是一个宏定义,原型是size_t,这个在标准C语言就是无符号短整形。这个函数的功能是:返回页面page中的剩余空间,实现机制很简单,定义一个变量space为page的pd_lower和pd_upper之差。如果space小于itemIdData的存储空间时,便返回0,说明无剩余空间了,否则返回space-sizeof(itemIdData),这里为什么要扣除一个itemIdData元组项的存储空间,还有待考证。 @H_502_2@ 今天的分析就到这里,希望其他同学发现不足,给予修改。 @H_502_2@ 姓名:鲁笛 主题:页面存储 原文链接:https://www.f2er.com/postgresql/194938.html