fix: create TSI MANIFEST files atomically (#23539) (#23575)

When a MANIFEST file is created in TSI, it
should be written to a temp file, then
atomically renamed, to avoid overwriting
the existing file only to fail on the
later write.

closes https://github.com/influxdata/influxdb/issues/23536

(cherry picked from commit 061cf55f2a)

closes https://github.com/influxdata/influxdb/issues/23537
pull/23576/head
davidby-influx 2022-07-20 14:21:21 -07:00 committed by GitHub
parent cbfc7c12c3
commit 05a0b540dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 1 deletions

View File

@ -1401,9 +1401,35 @@ func (m *Manifest) Write() (int64, error) {
}
buf = append(buf, '\n')
if err := os.WriteFile(m.path, buf, 0666); err != nil {
f, err := os.CreateTemp(filepath.Dir(m.path), ManifestFileName)
if err != nil {
return 0, err
}
tmp := f.Name()
// In correct operation, Remove() should fail because the file was renamed
defer os.Remove(tmp)
err = func() (rErr error) {
// Close() before rename for Windows
defer errors2.Capture(&rErr, f.Close)()
if _, err = f.Write(buf); err != nil {
return fmt.Errorf("failed writing temporary manifest file %q: %w", tmp, err)
}
return nil
}()
if err != nil {
return 0, err
}
if err = os.Chmod(tmp, 0666); err != nil {
return 0, err
}
if err = os.Rename(tmp, m.path); err != nil {
return 0, err
}
return int64(len(buf)), nil
}