通过本系列的学习可以学到什么?
WAL
预写日志的实现内存数据采用 SkipList
存储
通过 WAL (Write Ahead Log)
保证内存数据 durability
和 crash-safe
能力
easydb.Open
打开数据库 *DB
对象;*DB
内部基于 WAL
恢复内存数据 openAllMemtables
【就是读取 segment
文件,解析出一个个 LogRecord
保存到 skiplist
中】,同时将内存数据分成活跃内存和不可变内存【参考 LSM Tree结构】。每个内存对象 *memtable
内部除了定义 skiplist
记录内存数据,同时定义 *wal
对象记录磁盘,*wal
对象中的磁盘文件按照指定的大小分段保存(这里类似kafka中日志数据文件分段原理)db.Put
方法,内部通过 batch
开启写事物(对db上锁),将数据批量保存 batch
的 pendingWrites
中,然后在 batch.Commit
一次性全部保存到内存和预写日志中同时关闭写事物(对db解锁)db.Get
方法,内部通过 batch
开启读事物(对db上锁),读取所有的内存对象中的数据(倒序)方式,也就是从最近的内存对象 *memtable
开始读,读取结束,提交事物(关闭读事物,对db解锁)建议从下面 Open Get Put
这几个函数开始看起
package main
import (
"fmt"
"https://github.com/mgface2022/easydb"
"https://github.com/mgface2022/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)
}
defer func() {
_ = 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
日志文件按照 SegmentSize
分成一个个的段文件;32KB
为一块存储区域,存储 多个 chunk
实际数据chunk
由 7 字节 header
+ 数据 payload
组成;header
头包括 4字节校验码,2字节数据长度 1字节数据类型;校验码校验的范围为:【length + type + payload】确保数据没有损坏chunk
组成Ps:本项目主要参考 LotusDB 实现
All comments