小文件分析 - (二)

主數(shù)據(jù)庫文件頭之后的都是頁的內(nèi)容了扬跋,頁的分類主要有5種:b-tree 頁脆栋,overflow 頁,free 頁鸠匀,lock-byte頁以及pointer map page蕉斜。
主要使用到的是前三者,lock-byte頁只要是為了支持某些文件系統(tǒng)使用的是強制性加文件鎖缀棍,而pointer map page是為了支持 auto_vacuumincremental_vacuum模式宅此,這兩個以后再說。

頁的格式

空閑頁 free page

空閑頁分為chunkleaf爬范,前者存放著多個leaf空閑頁(里面沒有任何數(shù)據(jù))父腕,并且chunk會串起來成為一個freelist,官網(wǎng)是這么說的:The freelist is organized as a linked list of freelist trunk pages with each trunk page containing page numbers for zero or more freelist leaf pages.

Offset Size Description
0 4 下一個freelist chunk page的頁號
4 4 L=當(dāng)前chunk存放的freelist leaf page的數(shù)目
8 L*4 freelist leaf page頁號組成的數(shù)組青瀑,長度等于L

b-tree頁 B-tree page

關(guān)于b樹和b+樹的璧亮,參考博客:B樹與B+樹

b-tree頁格式

  • The 100-byte database file header (found on page 1 only)
  • The 8 or 12 byte b-tree page header
  • The cell pointer array
  • Unallocated space
  • The cell content area
  • The reserved region.

主數(shù)據(jù)庫文件頭只在頁1有,保留區(qū)間默認(rèn)也是沒有的斥难,所以剩下的就是

頁頭
cell指針數(shù)組
未使用區(qū)間
cell內(nèi)容區(qū)

先不著急看頁頭和cell的具體定義枝嘶,回到我們那個小文件分析中,還是利用剛才的showdb工具依次輸入./showdb small.db NbdCCC哑诊,N為頁號(例子中N=1~3):

PS G:\code-2\sqlite3> ./showdb small.db 1bdCCC
Pagesize: 4096
Available pages: 1..2
Header on btree page 1:
 000: 0d                   13  table leaf
 001: 00 00                 0  Offset to first freeblock
 003: 00 01                 1  Number of cells on this page
 005: 0f a3              4003  Offset to cell content area
 007: 00                    0  Fragmented byte count
Cell[0]:
 f3f: 5b                         payload-size: 91
 f40: 01                         rowid: 1
 f41: 07                         record-header-size: 7
 f42: 17                         typecode[0]: 23 - text(5)
 f43: 21                         typecode[1]: 33 - text(10)
 f44: 21                         typecode[2]: 33 - text(10)
 f45: 01                         typecode[3]: 1 - int8
 f46: 81 01                      typecode[4]: 129 - text(58)
 f48: 74 61 62 6c 65             data[0]: 'table'
 f4d: 64 65 70 61 72 74 6d 65 6e data[1]: 'department'
 f57: 64 65 70 61 72 74 6d 65 6e data[2]: 'department'
 f61: 02                         data[3]: 2
 f62: 43 52 45 41 54 45 20 54 41 data[4]: 'CREATE TABLE department...'

這里涉及提前涉及到了sqlite_schema的概念群扶,它存放著其他所有表、索引、觸發(fā)器對應(yīng)的根b-tree頁號竞阐,而這由一張?zhí)摂M的表組成缴饭,并且sqlite3默認(rèn)該表的根b-tree頁號為1。sqlite_schema的定義如下

CREATE TABLE sqlite_schema(
  type text,
  name text,
  tbl_name text,
  rootpage integer,
  sql text
);

暫時了解到這里即可馁菜,回頭看頁1茴扁,可以看到Cell[0]存放著的正是department這張表的信息,從里面我預(yù)先(可以先講格式汪疮,但這樣就很無聊了)知道了rootpage = 2(cell[0]里面的data[3]==2)峭火。
故而接著解析頁2,這時候我們就可以看到我們之前插入的兩條數(shù)據(jù):

PS G:\code-2\sqlite3> ./showdb small.db 2bdCCC
Pagesize: 4096
Available pages: 1..2
Header on btree page 2:
 000: 0d                   13  table leaf
 001: 00 00                 0  Offset to first freeblock
 003: 00 02                 2  Number of cells on this page
 005: 0f ea              4074  Offset to cell content area
 007: 00                    0  Fragmented byte count
Cell[0]:
 ff5: 09                         payload-size: 9
 ff6: 01                         rowid: 1
 ff7: 04                         record-header-size: 4
 ff8: 09                         typecode[0]: 9 - one
 ff9: 15                         typecode[1]: 21 - text(4)
 ffa: 01                         typecode[2]: 1 - int8
 ffb: 74 65 73 74                data[1]: 'test'
 fff: ff                         data[2]: -1
Cell[1]:
 fea: 09                         payload-size: 9
 feb: 02                         rowid: 2
 fec: 04                         record-header-size: 4
 fed: 01                         typecode[0]: 1 - int8
 fee: 15                         typecode[1]: 21 - text(4)
 fef: 09                         typecode[2]: 9 - one
 ff0: 02                         data[0]: 2
 ff1: 74 65 73 74                data[1]: 'test'

之前插入的兩條數(shù)據(jù)

sqlite> insert into department values(1, "test", -1);
sqlite> insert into department values(2, "test", 1);

結(jié)合上述數(shù)據(jù)再來分析頁頭以及別的數(shù)據(jù)格式的內(nèi)容智嚷。

b-tree 頁頭內(nèi)容

  • 偏移0x0 存放著的是b-tree頁的類型卖丸,總共有4種
    • 0x02 是 內(nèi)部索引 b-tree頁,interior index b-tree page
    • 0x05 是 內(nèi)部表 b-tree頁盏道,interior table b-tree page
    • 0x0a 是 葉節(jié)點索引 b-tree頁稍浆,leaf index b-tree page
    • 0x0d 是 葉節(jié)點表 b-tree頁,leaf table b-tree page
  • 偏移0x1和0x7猜嘱,是與cell被刪除的時候留下的磁盤碎片問題衅枫,大于等于4字節(jié)的磁盤碎片被稱為freeblock,串成一條鏈表朗伶,由page header存儲首個freeblock弦撩;小于4字節(jié)的被稱為fragment,并且會被累加到Fragmented byte count里面论皆。
  • 偏移0x03和0x05與cell有關(guān)益楼,前者存儲cell的個數(shù),后者存放cell內(nèi)容的起始偏移
  • 還有0x08處点晴,如果是 interior table b-tree page的話感凤,還會存放一個右子樹的頁號。
  • 剩下的就是cell指針數(shù)組了粒督。

那么問題來了陪竿,cell究竟是啥?cell我的理解就是上述四種節(jié)點的類型的具體存放內(nèi)容坠陈。來自官網(wǎng)的介紹

Datatype Table Leaf (0x0d) Table Interior (0x05) Index Leaf (0x0a) Index Interior (0x02) Description
4-byte integer ? ? Page number of left child
varint ? ? ? Number of bytes of payload
varint ? ? Rowid
byte array ? ? ? Payload
4-byte integer ? ? ? Page number of first overflow page

這里剩下的問題就是playload里面存放著什么了萨惑。不管是table還是index都是 "record format",也就是記錄列的個數(shù)仇矾,列的類型庸蔼,以及每一列的內(nèi)容。

對于Table Leaf來說贮匕,里面存放的就是一行數(shù)據(jù)姐仅,其格式如下:

record-header-size
record-header
data array
  • record-header-size:表明該記錄頭部+列的類型的大小。用的是可變長整型
  • record-header: 記錄每一列的類型serial type,也是一個可變長整型掏膏。與此同時它也承擔(dān)著該列內(nèi)容的長度劳翰。
  • data:則是每一列的內(nèi)容,整數(shù)由serial type定義長度馒疹,而字符串和二進(jìn)制數(shù)據(jù)長度由serial type給出佳簸,其余的值直接由serial type給出:

以下是serial type的定義:

Serial Type Content Size Meaning
0 0 Value is a NULL.
1 1 Value is an 8-bit twos-complement integer.
2 2 Value is a big-endian 16-bit twos-complement integer.
3 3 Value is a big-endian 24-bit twos-complement integer.
4 4 Value is a big-endian 32-bit twos-complement integer.
5 6 Value is a big-endian 48-bit twos-complement integer.
6 8 Value is a big-endian 64-bit twos-complement integer.
7 8 Value is a big-endian IEEE 754-2008 64-bit floating point number.
8 0 Value is the integer 0. (Only available for schema format 4 and higher.)
9 0 Value is the integer 1. (Only available for schema format 4 and higher.)
10,11 variable Reserved for internal use. These serial type codes will never appear in a well-formed database file, but they might be used in transient and temporary database files that SQLite sometimes generates for its own use. The meanings of these codes can shift from one release of SQLite to the next.
N≥12 and even (N-12)/2 Value is a BLOB that is (N-12)/2 bytes in length.
N≥13 and odd (N-13)/2 Value

舉個例子:

Cell[0]:
 ff5: 09                         payload-size: 9
 ff6: 01                         rowid: 1
 ff7: 04                         record-header-size: 4
 ff8: 09                         typecode[0]: 9 - one
 ff9: 15                         typecode[1]: 21 - text(4)
 ffa: 01                         typecode[2]: 1 - int8
 ffb: 74 65 73 74                data[1]: 'test'
 fff: ff                         data[2]: -1

該cell對應(yīng)著:insert into department values(1, "test", -1);
數(shù)據(jù)依次是:整數(shù)1,字符串"test"颖变,整數(shù)-1
整型生均,字符串,整型腥刹,這信息對應(yīng)著0xff8马胧,0xff9,0xffa衔峰,
其中字符串的長度 = (21 - 13)/2 = 4佩脊。那如果是奇數(shù)長度的字符串呢?
因為schema format是4垫卤,故1可以直接用 09來表示威彰。
……
剩下的就不說了。
不過有一點值得注意的是穴肘,這插入其實是逆序執(zhí)行的抱冷,回憶一下page的分布,cell content是從下往上伸展梢褐,而cell pointer array是從上往下伸展。故越新的數(shù)據(jù)赵讯,在越上面盈咳。這是為了減少頁的磁盤碎片化而使用的機制。

至此最簡單的一個數(shù)據(jù)庫文件已經(jīng)分析完边翼。但是還留下以下問題:

  • 1鱼响、overflow page 是怎么一回事?用在什么場景组底?
  • 2丈积、index 和 table 的 interior類型還沒有討論?
  • 3债鸡、vacuum 是什么一回事江滨?
  • 4、wal-mode 和 hot-journal mode 具體的意義厌均?
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唬滑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晶密,老刑警劉巖擒悬,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稻艰,居然都是意外死亡懂牧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門尊勿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來僧凤,“玉大人,你說我怎么就攤上這事运怖∑雌” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵摇展,是天一觀的道長吻氧。 經(jīng)常有香客問我,道長咏连,這世上最難降的妖魔是什么盯孙? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮祟滴,結(jié)果婚禮上振惰,老公的妹妹穿的比我還像新娘。我一直安慰自己垄懂,他們只是感情好骑晶,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著草慧,像睡著了一般桶蛔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漫谷,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天仔雷,我揣著相機與錄音,去河邊找鬼舔示。 笑死碟婆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惕稻。 我是一名探鬼主播竖共,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼俺祠!你這毒婦竟也來了肘迎?” 一聲冷哼從身側(cè)響起甥温,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妓布,沒想到半個月后姻蚓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡匣沼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年狰挡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片释涛。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡加叁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唇撬,到底是詐尸還是另有隱情它匕,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布窖认,位于F島的核電站豫柬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扑浸。R本人自食惡果不足惜烧给,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喝噪。 院中可真熱鬧础嫡,春花似錦、人聲如沸酝惧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晚唇。三九已至檬贰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缺亮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工桥言, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萌踱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓号阿,卻偏偏與公主長得像并鸵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子扔涧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容