-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - Fix nil pointer panic on error #5035
Conversation
2cba9d0
to
b813d79
Compare
Codecov Report
@@ Coverage Diff @@
## develop #5035 +/- ##
=======================================
Coverage 77.0% 77.0%
=======================================
Files 257 257
Lines 30242 30242
=======================================
+ Hits 23314 23315 +1
Misses 5401 5401
+ Partials 1527 1526 -1
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using atomic.WriteFile()
that takes an io.Reader
instead? It should simplify the code a lot (no need to remember to close the temporary file for instance).
It would make the code a bit shorter, but at the expense of requiring more memory: checksum := crc64.New(crc64.MakeTable(crc64.ISO))
if _, err := checksum.Write(data); err != nil {
return fmt.Errorf("calc checksum: %w", err)
}
buf := &bytes.Buffer{}
if _, err := buf.Write(data); err != nil {
return fmt.Errorf("write data %w", err)
}
crc := make([]byte, crc64.Size)
binary.BigEndian.PutUint64(crc, checksum.Sum64())
if _, err := buf.Write(crc); err != nil {
return fmt.Errorf("write checksum %w", err)
}
if err := atomic.WriteFile(path, buf); err != nil {
return fmt.Errorf("write file %s: %w", path, err)
}
return nil vs tmpName := fmt.Sprintf("%s.tmp", path)
tmp, err := os.Create(tmpName)
if err != nil {
return fmt.Errorf("create temporary file %s: %w", tmpName, err)
}
defer tmp.Close()
checksum := crc64.New(crc64.MakeTable(crc64.ISO))
w := io.MultiWriter(tmp, checksum)
if _, err := w.Write(data); err != nil {
return fmt.Errorf("write data %v: %w", tmp.Name(), err)
}
crc := make([]byte, crc64.Size)
binary.BigEndian.PutUint64(crc, checksum.Sum64())
if _, err := tmp.Write(crc); err != nil {
return fmt.Errorf("write checksum %s: %w", tmp.Name(), err)
}
if err := tmp.Close(); err != nil {
return fmt.Errorf("failed to close tmp file %s: %w", tmp.Name(), err)
}
if err := atomic.ReplaceFile(tmp.Name(), path); err != nil {
return fmt.Errorf("save file from %s, %s: %w", tmp.Name(), path, err)
}
return nil |
954ff60
to
ee39a22
Compare
bors merge |
## Motivation Closes #5034 ## Changes - do not call `tmp.Name()` on error since `tmp` might be `nil`. ## Test Plan n/a ## TODO <!-- This section should be removed when all items are complete --> - [x] Explain motivation or link existing issue(s) - [x] Test changes and document test plan - [x] Update documentation as needed - [x] Update [changelog](../CHANGELOG.md) as needed
@fasmat I was thinking about something like this: func write(path string, data []byte) error {
buf := bytes.NewBuffer(nil)
checksum := crc64.New(crc64.MakeTable(crc64.ISO))
w := io.MultiWriter(buf, checksum)
if _, err := w.Write(data); err != nil {
return fmt.Errorf("write data %v: %w", path, err)
}
if _, err := buf.Write(checksum.Sum(buf.AvailableBuffer())); err != nil {
return fmt.Errorf("write checksum %v: %w", path, err)
}
if err := atomic.WriteFile(path, buf); err != nil {
return fmt.Errorf("save file %v: %w", path, err)
}
return nil
} which I think is close to the original implementation by Kimmy. 💡 There is no need for |
Pull request successfully merged into develop. Build succeeded! The publicly hosted instance of bors-ng is deprecated and will go away soon. If you want to self-host your own instance, instructions are here. If you want to switch to GitHub's built-in merge queue, visit their help page. |
@poszu this is the benchmark I ran: func BenchmarkWriteCRC(b *testing.B) {
path := filepath.Join(b.TempDir(), "test.bin")
data := make([]byte, 4096)
rand.Read(data)
for i := 0; i < b.N; i++ {
require.NoError(b, write(path, data))
}
} with your suggested implementation I get
with the current implementation I get
The reason is that the current implementation doesn't require a buffer that the data is written to before it is written to disk, but rather writes it to disk directly. EDIT:
using |
Motivation
Closes #5034
Changes
tmp.Name()
on error sincetmp
might benil
.Test Plan
n/a
TODO