Skip to content

Commit 8323860

Browse files
authored
fix: update atomic fs writer to delay tmp creation until Write
Signed-off-by: Evan Baker <[email protected]>
1 parent 1edb63f commit 8323860

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

internal/fs/atomic.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import (
55
"io/fs"
66
"os"
77
"path"
8+
"sync"
89

910
"github.com/pkg/errors"
1011
)
1112

1213
type AtomicWriter struct {
1314
filename string
1415
tempFile *os.File
16+
17+
lock sync.Mutex
1518
}
1619

1720
var _ io.WriteCloser = &AtomicWriter{}
@@ -52,29 +55,39 @@ func NewAtomicWriter(filename string) (*AtomicWriter, error) {
5255
}
5356
}
5457

55-
tempFile, err := os.CreateTemp(path.Dir(filename), path.Base(filename)+"*.tmp")
56-
if err != nil {
57-
return nil, errors.Wrap(err, "unable to create temporary file")
58-
}
59-
60-
return &AtomicWriter{filename: filename, tempFile: tempFile}, nil
58+
return &AtomicWriter{filename: filename}, nil
6159
}
6260

63-
// Close closes the temp file handle and moves the temp file to the final destination
61+
// Close closes the temp file handle and moves the temp file to the final destination.
62+
// Multiple calls to Close will have no effect after the first success.
6463
func (a *AtomicWriter) Close() error {
65-
if err := a.tempFile.Close(); err != nil {
64+
a.lock.Lock()
65+
defer a.lock.Unlock()
66+
if a.tempFile == nil {
67+
return nil
68+
}
69+
if err := a.tempFile.Close(); err != nil && !errors.Is(err, os.ErrClosed) {
6670
return errors.Wrapf(err, "unable to close temp file %s", a.tempFile.Name())
6771
}
68-
6972
if err := os.Rename(a.tempFile.Name(), a.filename); err != nil {
7073
return errors.Wrapf(err, "unable to move temp file %s to destination %s", a.tempFile.Name(), a.filename)
7174
}
72-
75+
a.tempFile = nil
7376
return nil
7477
}
7578

76-
// Write writes the buffer to the temp file. You must call Close() to complete the move from temp file to dest file
79+
// Write writes the buffer to the temp file. You must call Close() to complete the move from temp file to dest file.
80+
// Multiple calls to Write will append to the temp file.
7781
func (a *AtomicWriter) Write(p []byte) (int, error) {
82+
a.lock.Lock()
83+
defer a.lock.Unlock()
84+
if a.tempFile == nil {
85+
tempFile, err := os.CreateTemp("", path.Base(a.filename)+"*.tmp")
86+
if err != nil {
87+
return 0, errors.Wrap(err, "unable to create temporary file")
88+
}
89+
a.tempFile = tempFile
90+
}
7891
bs, err := a.tempFile.Write(p)
7992
return bs, errors.Wrap(err, "unable to write to temp file")
8093
}

0 commit comments

Comments
 (0)