Disk Manager の実装について
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」17 日目の記事です。
はじめに
どうも、最近そろそろ DBMS 作るのでなく MySQL とかの勉強をしたいなと思い始めたけんつです。
今日はディスク周りの話です。
といってもすることがあまりないのでめちゃくちゃ短くなりそうです。
データの永続化
実装
今回は Direct I/O を使っていない
やっていることも簡単でファイルの RW だけ
一応 Page, SysPage 毎に分けているけどこれを書いていて、もう少し抽象化した方がいいなと思った
package storage import ( "io/ioutil" "os" "path" "path/filepath" "strconv" ) type DiskManager struct { } const ( RootDir = ".toybox" PagePrefix = "page_" SystemPageDirectory = "sys" SystemPageFileExt = ".json" ) func NewDisk() *DiskManager { return &DiskManager{} } func (d *DiskManager) SavePage(tableName string, pageId uint64, page *Page) error { buf, err := SerializePage(page) if err != nil { return err } tablePath := filepath.Join(RootDir, tableName) _, err = os.Stat(tablePath) if os.IsNotExist(err) { err := os.MkdirAll(tablePath, 0777) if err != nil { panic(err) } } pid := strconv.FormatUint(pageId, 10) pagePath := path.Join(RootDir, tableName, PagePrefix+pid) return ioutil.WriteFile(pagePath, buf[:], 0777) } func (d *DiskManager) SaveSystemPage(tableName string, sysPage *SystemPage) error { json := SerializeSystemPage(sysPage) tablePath := filepath.Join(RootDir, SystemPageDirectory) _, err := os.Stat(tablePath) if os.IsNotExist(err) { err := os.MkdirAll(tablePath, 0777) if err != nil { panic(err) } } sysPagePath := path.Join(RootDir, SystemPageDirectory, tableName+SystemPageFileExt) return ioutil.WriteFile(sysPagePath, json, 0777) } func (d *DiskManager) LoadPage(tableName string, pageId uint64) (*Page, error) { pid := strconv.FormatUint(pageId, 10) pagePath := path.Join(RootDir, tableName, PagePrefix+pid) _, err := os.Stat(pagePath) if os.IsNotExist(err) { return nil, err } bytes, err := ioutil.ReadFile(pagePath) if err != nil { return nil, err } var buf [PageByteSize]byte copy(buf[:], bytes) return DeserializePage(buf) } func (d *DiskManager) LoadSystemPage(tableName string) (*SystemPage, error) { pagePath := path.Join(RootDir, SystemPageDirectory, tableName+SystemPageFileExt) _, err := os.Stat(pagePath) if err != nil { return nil, err } bytes, err := ioutil.ReadFile(pagePath) if err != nil { return nil, err } return DeserializeSystemPage(bytes) } func (d *DiskManager) LoadAllSystemPage() (map[string]*SystemPage, error) { path := path.Join(RootDir, SystemPageDirectory) files, err := ioutil.ReadDir(path) if err != nil { return nil, err } systems := make(map[string]*SystemPage) for _, file := range files { p := filepath.Join(path, file.Name()) bytes, err := ioutil.ReadFile(p) if err != nil { return nil, err } sysPage, err := DeserializeSystemPage(bytes) if err != nil { return nil, err } systems[file.Name()[:len(file.Name())-5]] = sysPage } return systems, nil }
おわりに
次は、SystemPage (Catalog) の話なのでまた短い。