我一直在构建一个简单的数据存储,作为我的文档数据库系统模块的一部分,我将为教育目的而构建。
为了可靠地存储数据,我必须遵守ACID属性。下面显示的是我的保存方法。
func (document Document) Save() (hash string, err error) {
if err := os.MkdirAll(document.FileDirectory(), 0600); err != nil {
return "", err
}
file, err := os.Create(document.TmpFile())
if err != nil {
return "", err
}
file.Write(document.Data)
if err := file.Sync(); err != nil {
return "", err
}
file.Close()
if err := os.Rename(document.TmpFile(), document.File()); err != nil {
return "", err
}
return document.Hash(), nil
}
首先将数据(以[]字节为单位)保存到临时文件中。然后,该文件与file.Sync()
同步,以确保将数据写入持久存储。然后将临时文件重命名为新文件。
注意:
我选择存储数据文件的方式是spoolDir格式。意味着从数据生成的哈希的前两个字符用作父目录名称。哈希的以下两个字符用作后续目录名。文件名将是剩下的36个字符。临时文件只有后缀.tmp
,文件路径和文件名相同。此设计的灵感来自git
存储数据的方式。
问题: 我实现数据存储算法的方式是否足以确保数据可靠地持久化。
到目前为止答案: 关于目录同步以确保数据持久性的事情(我不确定)
提前致谢
根据rightfold的建议更新了代码:
func (document Document) Save() (hash string, err error) {
if err := os.MkdirAll(document.FileDirectory(), 0600); err != nil {
return "", err
}
file, err := os.Create(document.TmpFile())
if err != nil {
return "", err
}
file.Write(document.Data)
if err := file.Sync(); err != nil {
return "", err
}
file.Close()
if err := os.Rename(document.TmpFile(), document.File()); err != nil {
os.Remove(document.TmpFile())
return "", err
}
return document.Hash(), nil
}
答案 0 :(得分:4)
您正在做的事情保证了OS和硬件保证的程度(这是您能获得的最佳程度)。
它也是原子的;不完整的写入不会留下不完整的数据,即使CPU发生火灾。
重命名失败时,您可能希望删除临时文件:
if err := os.Rename(document.TmpFile(), document.File()); err != nil {
os.Remove(document.TmpFile()) // ignore errors
return "", err
}