I have been building a simple data store as part of my module for a document database system which I'm going to build for educational purposes.
In order to store data reliably, I have to abide the ACID property. Shown below is my save method.
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
}
First the data (in []byte) is saved to a temporary file. The file is then synced with file.Sync()
to ensure the data is written to the persistent storage. Then the temporary file is renamed into the new file.
Note:
The way i chose to store the data file is in spoolDir format. Meaning the first two character of the hash generated from the data is used as parent directory name. The following two character of the hash is used as the subsequent directory name. The filename will be the 36 character left over. The temporary file only has a suffix .tmp
with the file path and file name the same. This design is inspired by how git
store data.
Question: Is the way I implement the data storing algorithm sufficient to ensure the data is reliably persisted.
Answer so far: Something about directory syncing to ensure data durability (I'm not sure)
Thanks in advance
Updated code as per suggested by 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
}