使用Go语言编写可靠的数据存储

4

作为我要建立的文档数据库系统模块的一部分,我已经构建了一个简单的数据存储。

为了可靠地存储数据,我必须遵守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
}

首先,数据(以 []byte 格式)被保存到一个临时文件中。然后使用 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
}
1个回答

4

您所做的操作只能保证与操作系统和硬件同样程度的耐久性(这已经是最好的结果)。

此外,该操作也是原子化的;即使CPU烧毁,不完整的写入也不会留下不完整的数据。

在重命名失败时,您可能需要删除临时文件:

if err := os.Rename(document.TmpFile(), document.File()); err != nil {
    os.Remove(document.TmpFile()) // ignore errors
    return "", err
}

哇,谢谢你的回复。我会按照你建议的去做的。 - endyjasmi
我认为在Windows上,如果document.File()存在,os.Rename()将返回一个错误。而在其他操作系统上,它会很好地替换它。 - zserge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接