在allocatecursor裡,中有openread或openwrite時才建立。
前者只是分配空間,後者是初始化的一些補充
ppage = pcur->ppage;
trace((
"insert: table=%d nkey=%lld ndata=%d page=%d %s\n"
, pcur->pgnoroot, px->nkey, px->ndata, ppage->pgno,
loc==0?
"overwrite"
:"new entry"))
;
pcur->pgnoroot是當前表根節點所在頁面,ppage->pgno是當前要插入的頁面序號,虛擬機器在執行newrowid命令時會呼叫
sqlite3btreelast()------->movetoroot()--------->getandinitpage()
來給pcur->ppage賦值,其中pppage就是pcur->ppage的位址
rc =
sqlite3pagerget
(pbt->ppager, pgno,
(dbpage**)
&pdbpage, breadonly);if
( rc )
*pppage =
(mempage*
)sqlite3pagergetextra
(pdbpage);if
((*pppage)
->isinit==0)
}
if
( pcur )
在newdatabase的zeropage,寫完資料庫的頭100個自己後,就會跟著建立一張sqlite_master表,這張表的資料更新也和普通表一樣,在insertcell函式裡
data = ppage->adata;
assert
(&data[ppage->celloffset]
==ppage->acellidx )
; rc =
allocatespace
(ppage, sz,
&idx);if
( rc )
/* the allocatespace() routine guarantees the following properties
** if it returns successfully */
assert
( idx >=0)
;assert
( idx >= ppage->celloffset+
2*ppage->ncell+
2|| corrupt_db )
;assert
( idx+sz <=
(int
)ppage->pbt->usablesize )
; ppage->nfree -
=(u16)(2
+ sz);if
( ichild )
else
pins = ppage->acellidx + i*2;
//更新cell索引陣列
memmove
(pins+
2, pins,2*
(ppage->ncell - i));
put2byte
(pins, idx)
; ppage->ncell++
;/* increment the cell count */
//更新這一頁的cell數量if(
(++data[ppage->hdroffset+4]
)==0) data[ppage->hdroffset+3]
++;
allocatespace裡更新第乙個cell的偏移位址
top -
= nbyte;
put2byte
(&data[hdr+5]
, top)
;assert
( top+nbyte <=
(int
)ppage->pbt->usablesize )
;*pidx = top;
那麼ppage->acellidx和ppage->celloffset是**來的呢,在zeropage函式裡,會被newdatabase()和btreecreatetable()函式呼叫
data[hdr]=(
char
)flags;
first = hdr +
((flags&ptf_leaf)==0
?12:8
);memset
(&data[hdr+1]
,0,4
);data[hdr+7]
=0;put2byte
(&data[hdr+5]
, pbt->usablesize)
; ppage->nfree =
(u16)
(pbt->usablesize - first)
;decodeflags
(ppage, flags)
; ppage->celloffset = first;
ppage->adataend =
&data[pbt->usablesize]
; ppage->acellidx =
&data[first]
;
相關測試**如下
do_execsql_test btree01-1.1
看列印日誌,c(i) as (values(1) union all select i+1 from c where i<1)對應的應該是
insert: table=1 nkey=1 ndata=2 page=1 new entry
大概會在第1頁的1020位元組處寫入資料,之所以沒有寫入到資料庫的原因是,因為這個是臨時的,可以看位元組碼後面會執行到delete指令,還沒存到檔案之前就把這個cell給刪了,即把這些資料清0,呼叫關係
sqlite3btreedelete()----->dropcell()------>freespace()
但是我們知道第一頁在之前已經向檔案裡寫入了sqlite_master的資料了,而現在第一頁在記憶體裡的內容(pbt->ppage1)是清零的,為什麼最後在pager層寫檔案時
rc =
sqlite3oswrite
(ppager->fd, pdata, ppager->pagesize, offset)
;
這裡的pdata是原來檔案裡的資料,而不是清0後的資料
其實看上面這個就可以知道pbt->ppage1 被設為了0,而且p->pbt物件頁被釋放了
甚至在commit時,btree物件也被換掉了
我們再回過頭來看當時insert時的btree物件是哪來的
pcx->pbtx好像是乙個臨時物件
struct vdbecursor {
。。。。。。
btree *pbtx;
/* separate file holding temporary table */
所以這2個根本就不是同乙個btree物件
btree *pbt = db->adb[i]
.pbt;
//真實資料庫檔案對應的表
vdbecursor *pcx;
pcx->pbtx//臨時表,只在記憶體中存在
SQLite原始碼學習 36 Btree雜記
關鍵 如下 if pbt npage 0 只有在資料庫為空的時候才寫入,不為空的時候直接返回了,不會往下執行。30 tablelock 0 1 1 sqlite master 00 idb 0 root 1 write 1 首先定義字元陣列 161 tablelock ophelp idb p1 r...
redis原始碼學習之跳躍表
跳躍表對於我來說是乙個比較陌生的資料結構,因此花了一上午的時間先看了一蛤mit的公開課。網易雲課堂 mit跳躍表 什麼是跳躍表,有乙個很簡單的例子,有些地方的火車站跟高鐵站是同乙個站,有的地方只有火車站 假設現在的線路是a b c d e。其中a和c剛剛說的高鐵和火車站在一塊,其他的只有火車站,考慮...
Redis學習 鍊錶原始碼分析
0.前言 redis 中的鍊錶是以通用鍊錶的形式實現的,而對於鍊錶的用途來說,主要的功能就是增刪改查,所以對於查詢來說,redis其提供了乙個match函式指標,使用者負責實現其具體的匹配操作,從而實現通用化。涉及的檔案 adlist.h adlist.c 1.資料結構 typedef struct...