2021SC@SDUSC B树中的cell概念
一、cell是什么?
sqlite数据库文件被分为固定大小的页,所有的页由B+树模块管理。每个页要么是树中的页(内部页或者叶子页),要么是溢出页,或者是自由页(自由页通过单链表组织起来)。
树中的页(内部页和叶子页)被分成许多cell,一个cell包括一个(或者一部分)负载。Cell是已分配或者已释放的磁盘空间集合。页的内容见往期分析。
每个页被分为4个部分:
1.页头
2.Cell指针数组
3.未分配空间
4.Cell内容
struct CellInfo {
i64 nKey; /* The key for INTKEY tables, or nPayload otherwise */
u8 *pPayload; /* Pointer to the start of payload */
u32 nPayload; /* Bytes of payload */
u16 nLocal; /* Amount of payload held locally, not on overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
Cell指针数组从上向下增长,cell内容从下向上增长。Cell指针数组作为页内的一种目录,帮助把cell组织起来。
页头只包含本页的管理信息,并且总是存储在页的开头。
Cell被保存在页的最底部,向页开头的方向增长。Cell指针数组从页头之后的第一个byte开始,包含0个或者多个cell指针。每个cell指针是一个2byte整数,该整数指示了实际cell内容相对于页开头的偏移量。Cell指针按照相应的键值排序,尽管cell本身的存储不是按照顺序的。Cell指针数组的大小被存储在页头处偏移量为3的地方。
Cell是变长的字节字符串。一个cell保存了一个负载。Cell的结构如下图所示,size列的单位是byte。

对应btreeInt.h中注释如下:
** The content of a cell looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of the left child. Omitted if leaf flag is set.
** var Number of bytes of data. Omitted if the zerodata flag is set.
** var Number of bytes of key. Or the key itself if intkey flag is set.
** * Payload
** 4 First page of the overflow chain. Omitted if no overflow
**
** Overflow pages form a linked list. Each page except the last is completely
** filled with data (pagesize - 4 bytes). The last page can have as little
** as 1 byte of data.
**
** SIZE DESCRIPTION
** 4 Page number of next overflow page
** * Data
**
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
** file header points to the first in a linked list of trunk page. Each trunk
** page points to multiple leaf pages. The content of a leaf page is
** unspecified. A trunk page looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of next trunk page
** 4 Number of leaf pointers on this page
** * zero or more pages numbers of leaves
对于内部节点,每个cell包含一个4byte的子节点指针;对于叶子节点,cell没有子节点指针。接下来是该cell存储的数据的大小(bytes)和存储的键值的大小(bytes)
(如果页头中的intkey为真,那么存储键值大小的地方就直接存储键值本身的整型值,如果zerodata为真,那么数据部分不存在)。
二、cell与溢出页结构
1.溢出页的意义
SQLite限制了每页中负载的数量。负载有可能不会把自身的全部存储在同一页中,尽管可能该页有足够大的空间。每页能够存储的最大单个负载由该页可用空间(可以被内部节点的单个cell使用)的总大小决定。
如果内部节点中的cell的负载大于最大负载限制,超出的部分就被分割并存储到溢出页链表中。一但分配了一个溢出页,要把尽可能多的字节转移到溢出页中,只要不导致cell的大小低于最小负载限制就行。对于叶子节点,最小负载限制存储在文件头内偏移量23处,但是最大负载限制总是100%,并且不会在文件头给出。
static int getOverflowPage(
BtShared *pBt, /* The database file */
Pgno ovfl, /* Current overflow page number */
MemPage **ppPage, /* OUT: MemPage handle (may be NULL) */
Pgno *pPgnoNext /* OUT: Next overflow page number */
){
Pgno next = 0;
MemPage *pPage = 0;
int rc = SQLITE_OK;
assert( sqlite3_mutex_held(pBt->mutex) );
assert(pPgnoNext);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* Try to find the next page in the overflow list using the
** autovacuum pointer-map pages. Guess that the next page in
** the overflow list is page number (ovfl+1). If that guess turns
** out to be wrong, fall back to loading the data of page
** number ovfl to determine the next page number.
*/
if( pBt->autoVacuum ){
Pgno pgno;
Pgno iGuess = ovfl+1;
u8 eType;
while

最低0.47元/天 解锁文章
936

被折叠的 条评论
为什么被折叠?



