mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/fs: replace WriteFileAndSync with MustWriteAndSync
When WriteFileAndSync fails, then the caller eventually logs the error message and exits. The error message returned by WriteFileAndSync already contains the path to the file, which couldn't be created. This information alongside the call stack is enough for debugging the issue. So just use log.Panicf("FATAL: ...") inside MustWriteAndSync(). This simplifies error handling at caller side a bit.
This commit is contained in:
parent
25f089de9d
commit
2a8395be05
7 changed files with 31 additions and 54 deletions
13
lib/fs/fs.go
13
lib/fs/fs.go
|
@ -25,7 +25,7 @@ func MustSyncPath(path string) {
|
||||||
mustSyncPath(path)
|
mustSyncPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteFileAndSync writes data to the file at path and then calls fsync on the created file.
|
// MustWriteFileAndSync writes data to the file at path and then calls fsync on the created file.
|
||||||
//
|
//
|
||||||
// The fsync guarantees that the written data survives hardware reset after successful call.
|
// The fsync guarantees that the written data survives hardware reset after successful call.
|
||||||
//
|
//
|
||||||
|
@ -33,20 +33,19 @@ func MustSyncPath(path string) {
|
||||||
// in the middle of the write.
|
// in the middle of the write.
|
||||||
// Use WriteFileAtomically if the file at the path must be either written in full
|
// Use WriteFileAtomically if the file at the path must be either written in full
|
||||||
// or not written at all on app crash in the middle of the write.
|
// or not written at all on app crash in the middle of the write.
|
||||||
func WriteFileAndSync(path string, data []byte) error {
|
func MustWriteFileAndSync(path string, data []byte) {
|
||||||
f, err := filestream.Create(path, false)
|
f, err := filestream.Create(path, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
logger.Panicf("FATAL: cannot create file: %s", err)
|
||||||
}
|
}
|
||||||
if _, err := f.Write(data); err != nil {
|
if _, err := f.Write(data); err != nil {
|
||||||
f.MustClose()
|
f.MustClose()
|
||||||
// Do not call MustRemoveAll(path), so the user could inspect
|
// Do not call MustRemoveAll(path), so the user could inspect
|
||||||
// the file contents during investigation of the issue.
|
// the file contents during investigation of the issue.
|
||||||
return fmt.Errorf("cannot write %d bytes to %q: %w", len(data), path, err)
|
logger.Panicf("FATAL: cannot write %d bytes to %q: %s", len(data), path, err)
|
||||||
}
|
}
|
||||||
// Sync and close the file.
|
// Sync and close the file.
|
||||||
f.MustClose()
|
f.MustClose()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteFileAtomically atomically writes data to the given file path.
|
// WriteFileAtomically atomically writes data to the given file path.
|
||||||
|
@ -70,9 +69,7 @@ func WriteFileAtomically(path string, data []byte, canOverwrite bool) error {
|
||||||
// Write data to a temporary file.
|
// Write data to a temporary file.
|
||||||
n := atomic.AddUint64(&tmpFileNum, 1)
|
n := atomic.AddUint64(&tmpFileNum, 1)
|
||||||
tmpPath := fmt.Sprintf("%s.tmp.%d", path, n)
|
tmpPath := fmt.Sprintf("%s.tmp.%d", path, n)
|
||||||
if err := WriteFileAndSync(tmpPath, data); err != nil {
|
MustWriteFileAndSync(tmpPath, data)
|
||||||
return fmt.Errorf("cannot write data to temporary file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atomically move the temporary file from tmpPath to path.
|
// Atomically move the temporary file from tmpPath to path.
|
||||||
if err := os.Rename(tmpPath, path); err != nil {
|
if err := os.Rename(tmpPath, path); err != nil {
|
||||||
|
|
|
@ -38,24 +38,19 @@ func (mp *inmemoryPart) StoreToDisk(path string) error {
|
||||||
return fmt.Errorf("cannot create directory %q: %w", path, err)
|
return fmt.Errorf("cannot create directory %q: %w", path, err)
|
||||||
}
|
}
|
||||||
metaindexPath := filepath.Join(path, metaindexFilename)
|
metaindexPath := filepath.Join(path, metaindexFilename)
|
||||||
if err := fs.WriteFileAndSync(metaindexPath, mp.metaindexData.B); err != nil {
|
fs.MustWriteFileAndSync(metaindexPath, mp.metaindexData.B)
|
||||||
return fmt.Errorf("cannot store metaindex: %w", err)
|
|
||||||
}
|
|
||||||
indexPath := filepath.Join(path, indexFilename)
|
indexPath := filepath.Join(path, indexFilename)
|
||||||
if err := fs.WriteFileAndSync(indexPath, mp.indexData.B); err != nil {
|
fs.MustWriteFileAndSync(indexPath, mp.indexData.B)
|
||||||
return fmt.Errorf("cannot store index: %w", err)
|
|
||||||
}
|
|
||||||
itemsPath := filepath.Join(path, itemsFilename)
|
itemsPath := filepath.Join(path, itemsFilename)
|
||||||
if err := fs.WriteFileAndSync(itemsPath, mp.itemsData.B); err != nil {
|
fs.MustWriteFileAndSync(itemsPath, mp.itemsData.B)
|
||||||
return fmt.Errorf("cannot store items: %w", err)
|
|
||||||
}
|
|
||||||
lensPath := filepath.Join(path, lensFilename)
|
lensPath := filepath.Join(path, lensFilename)
|
||||||
if err := fs.WriteFileAndSync(lensPath, mp.lensData.B); err != nil {
|
fs.MustWriteFileAndSync(lensPath, mp.lensData.B)
|
||||||
return fmt.Errorf("cannot store lens: %w", err)
|
|
||||||
}
|
mp.ph.MustWriteMetadata(path)
|
||||||
if err := mp.ph.WriteMetadata(path); err != nil {
|
|
||||||
return fmt.Errorf("cannot store metadata: %w", err)
|
|
||||||
}
|
|
||||||
fs.MustSyncPath(path)
|
fs.MustSyncPath(path)
|
||||||
// Do not sync parent directory - it must be synced by the caller.
|
// Do not sync parent directory - it must be synced by the caller.
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -113,7 +113,7 @@ func (ph *partHeader) ReadMetadata(partPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *partHeader) WriteMetadata(partPath string) error {
|
func (ph *partHeader) MustWriteMetadata(partPath string) {
|
||||||
phj := &partHeaderJSON{
|
phj := &partHeaderJSON{
|
||||||
ItemsCount: ph.itemsCount,
|
ItemsCount: ph.itemsCount,
|
||||||
BlocksCount: ph.blocksCount,
|
BlocksCount: ph.blocksCount,
|
||||||
|
@ -128,8 +128,5 @@ func (ph *partHeader) WriteMetadata(partPath string) error {
|
||||||
// There is no need in calling fs.WriteFileAtomically() here,
|
// There is no need in calling fs.WriteFileAtomically() here,
|
||||||
// since the file is created only once during part creatinng
|
// since the file is created only once during part creatinng
|
||||||
// and the part directory is synced aftewards.
|
// and the part directory is synced aftewards.
|
||||||
if err := fs.WriteFileAndSync(metadataPath, metadata); err != nil {
|
fs.MustWriteFileAndSync(metadataPath, metadata)
|
||||||
return fmt.Errorf("cannot create %q: %w", metadataPath, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1245,9 +1245,7 @@ func (tb *Table) mergePartsInternal(dstPartPath string, bsw *blockStreamWriter,
|
||||||
return nil, fmt.Errorf("cannot merge %d parts to %s: %w", len(bsrs), dstPartPath, err)
|
return nil, fmt.Errorf("cannot merge %d parts to %s: %w", len(bsrs), dstPartPath, err)
|
||||||
}
|
}
|
||||||
if dstPartPath != "" {
|
if dstPartPath != "" {
|
||||||
if err := ph.WriteMetadata(dstPartPath); err != nil {
|
ph.MustWriteMetadata(dstPartPath)
|
||||||
logger.Panicf("FATAL: cannot write metadata to %s: %s", dstPartPath, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return &ph, nil
|
return &ph, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,24 +41,19 @@ func (mp *inmemoryPart) StoreToDisk(path string) error {
|
||||||
return fmt.Errorf("cannot create directory %q: %w", path, err)
|
return fmt.Errorf("cannot create directory %q: %w", path, err)
|
||||||
}
|
}
|
||||||
timestampsPath := filepath.Join(path, timestampsFilename)
|
timestampsPath := filepath.Join(path, timestampsFilename)
|
||||||
if err := fs.WriteFileAndSync(timestampsPath, mp.timestampsData.B); err != nil {
|
fs.MustWriteFileAndSync(timestampsPath, mp.timestampsData.B)
|
||||||
return fmt.Errorf("cannot store timestamps: %w", err)
|
|
||||||
}
|
|
||||||
valuesPath := filepath.Join(path, valuesFilename)
|
valuesPath := filepath.Join(path, valuesFilename)
|
||||||
if err := fs.WriteFileAndSync(valuesPath, mp.valuesData.B); err != nil {
|
fs.MustWriteFileAndSync(valuesPath, mp.valuesData.B)
|
||||||
return fmt.Errorf("cannot store values: %w", err)
|
|
||||||
}
|
|
||||||
indexPath := filepath.Join(path, indexFilename)
|
indexPath := filepath.Join(path, indexFilename)
|
||||||
if err := fs.WriteFileAndSync(indexPath, mp.indexData.B); err != nil {
|
fs.MustWriteFileAndSync(indexPath, mp.indexData.B)
|
||||||
return fmt.Errorf("cannot store index: %w", err)
|
|
||||||
}
|
|
||||||
metaindexPath := filepath.Join(path, metaindexFilename)
|
metaindexPath := filepath.Join(path, metaindexFilename)
|
||||||
if err := fs.WriteFileAndSync(metaindexPath, mp.metaindexData.B); err != nil {
|
fs.MustWriteFileAndSync(metaindexPath, mp.metaindexData.B)
|
||||||
return fmt.Errorf("cannot store metaindex: %w", err)
|
|
||||||
}
|
mp.ph.MustWriteMetadata(path)
|
||||||
if err := mp.ph.WriteMetadata(path); err != nil {
|
|
||||||
return fmt.Errorf("cannot store metadata: %w", err)
|
|
||||||
}
|
|
||||||
fs.MustSyncPath(path)
|
fs.MustSyncPath(path)
|
||||||
// Do not sync parent directory - it must be synced by the caller.
|
// Do not sync parent directory - it must be synced by the caller.
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -165,7 +165,7 @@ func (ph *partHeader) ReadMetadata(partPath string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ph *partHeader) WriteMetadata(partPath string) error {
|
func (ph *partHeader) MustWriteMetadata(partPath string) {
|
||||||
metadata, err := json.Marshal(ph)
|
metadata, err := json.Marshal(ph)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Panicf("BUG: cannot marshal partHeader metadata: %s", err)
|
logger.Panicf("BUG: cannot marshal partHeader metadata: %s", err)
|
||||||
|
@ -174,8 +174,5 @@ func (ph *partHeader) WriteMetadata(partPath string) error {
|
||||||
// There is no need in calling fs.WriteFileAtomically() here,
|
// There is no need in calling fs.WriteFileAtomically() here,
|
||||||
// since the file is created only once during part creatinng
|
// since the file is created only once during part creatinng
|
||||||
// and the part directory is synced aftewards.
|
// and the part directory is synced aftewards.
|
||||||
if err := fs.WriteFileAndSync(metadataPath, metadata); err != nil {
|
fs.MustWriteFileAndSync(metadataPath, metadata)
|
||||||
return fmt.Errorf("cannot create %q: %w", metadataPath, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1465,9 +1465,7 @@ func (pt *partition) mergePartsInternal(dstPartPath string, bsw *blockStreamWrit
|
||||||
}
|
}
|
||||||
if dstPartPath != "" {
|
if dstPartPath != "" {
|
||||||
ph.MinDedupInterval = GetDedupInterval()
|
ph.MinDedupInterval = GetDedupInterval()
|
||||||
if err := ph.WriteMetadata(dstPartPath); err != nil {
|
ph.MustWriteMetadata(dstPartPath)
|
||||||
logger.Panicf("FATAL: cannot store metadata to %s: %s", dstPartPath, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return &ph, nil
|
return &ph, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue