Golang實現(xiàn)KV存儲引擎實例探究
引言
通過本項目可以學(xué)到什么?
WAL預(yù)寫日志的實現(xiàn)
LSM Tree(Log-Structed-Merge Tree)
如何構(gòu)架一個企業(yè)級的項目
KV數(shù)據(jù)的序列化和反序列化存儲
- Golang的基本語法
整個代碼量1000多行,基本的大框架也好理解,容易出現(xiàn)錯誤的點在于代碼細(xì)節(jié)的處理(特別是wal文件的讀寫部分)

簡介
內(nèi)存數(shù)據(jù)采用SkipList 存儲
通過WAL (Write Ahead Log)保證內(nèi)存數(shù)據(jù)durability和crash-safe能力

代碼邏輯結(jié)構(gòu)

- 先通過
easydb.Open打開數(shù)據(jù)庫*DB對象;*DB內(nèi)部基于WAL恢復(fù)內(nèi)存數(shù)據(jù)openAllMemtables【就是讀取segment文件,解析出一個個LogRecord保存到skiplist中】,同時將內(nèi)存數(shù)據(jù)分成活躍內(nèi)存和不可變內(nèi)存【參考 LSM Tree結(jié)構(gòu)】。每個內(nèi)存對象*memtable內(nèi)部除了定義skiplist記錄內(nèi)存數(shù)據(jù),同時定義*wal對象記錄磁盤,*wal對象中的磁盤文件按照指定的大小分段保存(這里類似kafka中日志數(shù)據(jù)文件分段原理) - 然后調(diào)用
db.Put方法,內(nèi)部通過batch開啟寫事物(對db上鎖),將數(shù)據(jù)批量保存batch的pendingWrites中,然后在batch.Commit一次性全部保存到內(nèi)存和預(yù)寫日志中同時關(guān)閉寫事物(對db解鎖) - 調(diào)用
db.Get方法,內(nèi)部通過batch開啟讀事物(對db上鎖),讀取所有的內(nèi)存對象中的數(shù)據(jù)(倒序)方式,也就是從最近的內(nèi)存對象*memtable開始讀,讀取結(jié)束,提交事物(關(guān)閉讀事物,對db解鎖)
建議從下面 Open Get Put這幾個函數(shù)開始看起
package main
import (
"fmt"
"github.com/gofish2020/easydb"
"github.com/gofish2020/easydb/utils"
)
// this file shows how to use the basic operations of EasyDB
func main() {
// specify the options
options := easydb.DefaultOptions
options.DirPath = utils.ExecDir() + "/data"
// open a database
db, err := easydb.Open(options)
if err != nil {
panic(err)
}
deferfunc() {
_ = db.Close()
}()
// put a key
err = db.Put([]byte("name"), []byte("easydb"), nil)
if err != nil {
panic(err)
}
// get a key
val, err := db.Get([]byte("name"))
if err != nil {
panic(err)
}
println(string(val))
// delete a key
err = db.Delete([]byte("name"), nil)
if err != nil {
panic(err)
}
// get a key
val, err = db.Get([]byte("name"))
if err != nil {
if err == easydb.ErrKeyNotFound {
fmt.Println("key not exist")
return
}
panic(err)
}
println(string(val))
}WAL日志格式

WAL日志文件按照SegmentSize分成一個個的段文件;
每個段文件,按照32KB為一塊存儲區(qū)域,存儲 多個 chunk實際數(shù)據(jù)
每個chunk由 7 字節(jié)header + 數(shù)據(jù)payload 組成;header頭包括 4字節(jié)校驗碼,2字節(jié)數(shù)據(jù)長度 1字節(jié)數(shù)據(jù)類型;校驗碼校驗的范圍為:【length + type + payload】確保數(shù)據(jù)沒有損壞
一個數(shù)據(jù)可能由多個chunk組成

當(dāng)在block中保存了多個chunk后,block剩余的空間不夠保存數(shù)據(jù),多余的空間浪費掉,填充一些無效字節(jié)即可

Ps:本項目主要參考 LotusDB 實現(xiàn)
以上就是Golang實現(xiàn)KV存儲引擎實例探究的詳細(xì)內(nèi)容,更多關(guān)于Golang KV存儲引擎的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang?gorm的Callbacks事務(wù)回滾對象操作示例
這篇文章主要為大家介紹了golang?gorm的Callbacks事務(wù)回滾對象操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
更換GORM默認(rèn)SQLite驅(qū)動出現(xiàn)的問題解決分析
這篇文章主要為大家介紹了更換GORM默認(rèn)SQLite驅(qū)動出現(xiàn)的問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
golang 數(shù)組去重,利用map的實現(xiàn)
這篇文章主要介紹了golang 數(shù)組去重,利用map的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
Golang實現(xiàn)smtp郵件發(fā)送的示例代碼
這篇文章主要為大家詳細(xì)介紹了Golang實現(xiàn)smtp郵件發(fā)送的相關(guān)知識,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03

