之前排查智能合約執行返回0x的問題,涉及到數據庫部分的內容,就把leveldb的3個主要操作介紹一下。
在此之間先介紹下leveldb中的文件類型。
文件類型
文件類型總共有5種:log, ldb, CURRENT, MANIFEST,LOG。 另外還有一部分內存緩存。
內存緩存:memtable。默認是32M大小。memtable寫滿之後會轉爲frozenmemtable,用於寫入數據庫
log文件:所有的put操作,數據都是先寫入log文件,然後才寫入內存memtable。作用是用於恢復數據,避免數據丟失。
ldb文件:kv數據庫文件。每一個數據庫中kv都是有序存儲的。
L0層的ldb文件可能存在key範圍重疊的情況。
L1~~Lk層的ldb文件不存在key範圍重疊的情況
CURRENT文件:記錄當前使用的MANIFEST文件名。
MANIFEST文件:記錄ldb文件對應的最小和最大key。
LOG文件:日誌,記錄表合併的日誌。
LOCK文件:鎖文件。每次以寫模式打開LOG文件時,先以只讀模式打開LOCK文件直到LOG文件關閉
put操作
put操作實際上不涉及到磁盤操作,只是將數據追加到log文件中,然後寫入memtable。如果memtable中數據沒能及時寫入到磁盤中,則通過log文件進行恢復。
get操作
get操作的簡單流程如下:
1、查詢memtable,找到就返回
2、查詢frozenmemtable,找到就返回
3、遍歷L0層的所有table的索引 ,找到就轉第5步,找不到轉第4步 。(L0層表的minkey,maxkey 可能存在重疊,此處的遍歷實際上是先查新表,再查舊錶。)
4、遍歷L1+N層的所有table的索引,找到就轉第5步,找不到結束。(根據每個table的最小和最大key進行比較,因爲是有序的,所以每個文件都只需要比較minkey和maxkey即可確定目標key在那個文件中)
5、查詢找到的表的緩存數據,查到就返回,查不到就轉第6步
6、打開表,遍歷表數據進行比較,找到就返回正確結果,找不到就返回錯誤。
compaction過程
compaction操作分爲兩種,一種是memcompaction,一種是tablecompaction
a、memcompaction
目標是將frozenmemtable寫入到L0中,
觸發條件:memtable寫滿了,就需要將memtable轉爲frozenmemtable,然後創建新的memtable。
流程如下
1、獲取frozenmemtable。
2、如果len(frozenmemtable) ==0 ,直接結束。否則,繼續第3步
3、停止tableComPaction。(memcompaction 和 tablecompaction不同時進行)
4、創建新的table,將frozenMemDb中的數據寫入新的table中,如果失敗了就刪除新建的表並結束。
5、將新的table信息寫入MANIFEST文件。
6、刪除frozenMemDb,恢復tablecompaction。
b、tablecompaction
目標是合併Lk層的表到Lk+1層,k>=0。
觸發合併條件有2個:1,某一層的數據大小滿了,2、某一層數據沒有命中,需要到下一層查詢,就需要將沒有命中的表合併到下一層去。
1、根據以上兩個條件,獲取需要合併的表tables,包括了Lk---->Lk+1層的表。k+1層的表可能是多個,因爲可能存在k層的表中的key與k+1層的多個表範圍重疊。
2、將數據從tables表中讀出來,寫入到新的newtable中
3、新的newtable寫滿後,會在創建新的表,然後繼續寫入。
4、將舊的表及舊錶相關的內存信息刪除
5、合併完畢。
表comaction的好處
1、減少存儲空間。刪除無效的key,以及合併相同的key或者相同前綴的key。
2、提高查詢效率。合併後數據都是有序的,因此查詢效率高。
思考
從之前排查的智能合約的例子看,tablecompaction的操作是比較耗時的,而且隨着數據量越來越大,耗時就越來越多。從區塊鏈的角度看,這無疑會成爲一個性能瓶頸。
從應用層角度看,智能合約的編寫更應該注重效率,減少數據庫的讀寫次數。
從數據庫角度看,只要進行tablecompaction操作,表就有被合併的可能。如果考慮單獨增加常用緩存的話,也要考慮緩存的更新和刪除問題,這是個值得思考的問題。再想想。。。。。。