当段中数据较少的时候,首先会查看表空间中是否有状态为 FREE_FRAG 的区,也就是找还有空闲空间的碎片区,如果找到了,那么从该区中取一些零碎的页把数据插进去;否则到表空间下申请一个状态为 FREE 的区,也就是空闲的区,把该区的状态变为 FREE_FRAG ,然后从该新申请的区中取一些零碎的页把数据插进去。之后不同的段使用零碎页的时候都会从该区中取,直到该区中没有空闲空间,然后该区的状态就变成了FULL_FRAG 。
现在的问题是你怎么知道表空间里的哪些区是 FREE 的,哪些区的状态是 FREE_FRAG 的,哪些区是FULL_FRAG 的?要知道表空间的大小是可以不断增大的,当增长到GB级别的时候,区的数量也就上千了,我们总不能每次都遍历这些区对应的 XDES Entry 结构吧?这时候就是 XDES Entry 中的 List Node 部分发挥奇效的时候了,我们可以通过 List Node 中的指针,做这么三件事:
- 把状态为 FREE 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表我们就称之为 FREE 链表。
- 把状态为 FREE_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表我们就称之为 FREE_FRAG 链表。
- 把状态为 FULL_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表我们就称之为 FULL_FRAG 链表。
这样每当我们想找一个 FREE_FRAG 状态的区时,就直接把 FREE_FRAG 链表的头节点拿出来,从这个节点中取一些零碎的页来插入数据,当这个节点对应的区用完时,就修改一下这个节点的 State 字段的值,然后从 FREE_FRAG 链表中移到 FULL_FRAG 链表中。同理,如果 FREE_FRAG 链表中一个节点都没有,那么就直接从 FREE 链表中取一个节点移动到 FREE_FRAG 链表的状态,并修改该节点的 STATE 字段值为FREE_FRAG ,然后从这个节点对应的区中获取零碎的页就好了。
当段中数据已经占满了32个零散的页后,就直接申请完整的区来插入数据了。
9.2.3.2 链表基节点
如何找到这些链表,怎么找到某个链表的头节点或者尾节点在表空间中的位置,这就需要List Base Node的结构。这个结构中包含了链表的头节点和尾节点的指针以及这个链表中包含了多少节点的信息,我们画图看一下这个结构的示意图:
我们上边介绍的每个链表都对应这么一个 List Base Node 结构,其中:
- List Length 表明该链表一共有多少节点。
- First Node Page Number 和 First Node Offset 表明该链表的头节点在表空间中的位置。
- Last Node Page Number 和 Last Node Offset 表明该链表的尾节点在表空间中的位置。
一般我们把某个链表对应的 List Base Node 结构放置在表空间中固定的位置,这样想找定位某个链表就容易多了。
9.2.3.3 链表小结
综上所述,表空间是由若干个区组成的,每个区都对应一个 XDES Entry 的结构,直属于表空间的区对应的 XDESEntry 结构可以分成 FREE 、 FREE_FRAG 和 FULL_FRAG 这3个链表;每个段可以附属若干个区,每个段中的区对应的 XDES Entry 结构可以分成 FREE 、 NOT_FULL 和 FULL 这3个链表。每个链表都对应一个 List Base Node 的结构,这个结构里记录了链表的头、尾节点的位置以及该链表中包含的节点数。正是因为这些链表的存在,管理这些区才容易不少。