Skip to content

Commit a334b20

Browse files
dobractttboy123
authored andcommitted
fix(storage): truncate local files on overwrite
Co-authored-by: Boyce <95002055+tttboy123@users.noreply.github.com> GitOrigin-RevId: 35cc85a6c6180b32415855a5a810f1ceda10b8b8
1 parent 75892fd commit a334b20

2 files changed

Lines changed: 334 additions & 20 deletions

File tree

‎packages/shared/pkg/storage/storage_fs.go‎

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,7 @@ func (o *fsObject) WriteTo(ctx context.Context, dst io.Writer) (n int64, err err
118118
}
119119

120120
func (o *fsObject) Put(_ context.Context, data []byte, _ ...PutOption) error {
121-
handle, err := o.getHandle(false)
122-
if err != nil {
123-
return err
124-
}
125-
defer handle.Close()
126-
127-
_, err = io.Copy(handle, bytes.NewReader(data))
121+
_, err := o.replaceFrom(bytes.NewReader(data))
128122

129123
return err
130124
}
@@ -155,23 +149,27 @@ func (o *fsObject) StoreFile(ctx context.Context, path string, opts ...PutOption
155149
}
156150
defer r.Close()
157151

158-
handle, err := o.getHandle(false)
152+
srcInfo, err := r.Stat()
159153
if err != nil {
160-
return nil, [32]byte{}, err
154+
return nil, [32]byte{}, fmt.Errorf("failed to stat file %s: %w", path, err)
155+
}
156+
if dstInfo, statErr := os.Stat(o.path); statErr == nil && os.SameFile(srcInfo, dstInfo) {
157+
return nil, [32]byte{}, nil
161158
}
162-
defer handle.Close()
163159

164-
n, err := io.Copy(handle, r)
165-
if err == nil {
166-
logger.L().Debug(ctx, "Stored file to filesystem",
167-
zap.String("object", o.path),
168-
zap.String("source", path),
169-
zap.Int64("size_uncompressed", n),
170-
zap.String("compression", "none"),
171-
)
160+
n, err := o.replaceFrom(r)
161+
if err != nil {
162+
return nil, [32]byte{}, err
172163
}
173164

174-
return nil, [32]byte{}, err
165+
logger.L().Debug(ctx, "Stored file to filesystem",
166+
zap.String("object", o.path),
167+
zap.String("source", path),
168+
zap.Int64("size_uncompressed", n),
169+
zap.String("compression", "none"),
170+
)
171+
172+
return nil, [32]byte{}, nil
175173
}
176174

177175
func (o *fsObject) storeFileCompressed(ctx context.Context, localPath string, cfg CompressConfig, sink FrameSink) (*FullFrameTable, [32]byte, error) {
@@ -298,6 +296,60 @@ func (o *fsObject) getHandle(checkExistence bool) (*os.File, error) {
298296
return handle, nil
299297
}
300298

299+
func replaceFile(path string, r io.Reader) (int64, error) {
300+
dir := filepath.Dir(path)
301+
if err := os.MkdirAll(dir, 0o755); err != nil {
302+
return 0, err
303+
}
304+
305+
tmp, err := os.CreateTemp(dir, "."+filepath.Base(path)+".tmp-*")
306+
if err != nil {
307+
return 0, err
308+
}
309+
tmpPath := tmp.Name()
310+
defer os.Remove(tmpPath)
311+
312+
if err := tmp.Chmod(0o644); err != nil {
313+
tmp.Close()
314+
315+
return 0, err
316+
}
317+
318+
n, err := io.Copy(tmp, r)
319+
if err != nil {
320+
tmp.Close()
321+
322+
return n, err
323+
}
324+
if err := tmp.Close(); err != nil {
325+
return n, err
326+
}
327+
328+
if err := os.Rename(tmpPath, path); err != nil {
329+
return n, err
330+
}
331+
332+
return n, nil
333+
}
334+
335+
func (o *fsObject) replaceFrom(r io.Reader) (int64, error) {
336+
n, err := replaceFile(o.path, r)
337+
if err != nil {
338+
return n, err
339+
}
340+
341+
return n, o.clearSizeSidecar()
342+
}
343+
344+
func (o *fsObject) clearSizeSidecar() error {
345+
err := os.Remove(SizeSidecar(o.path))
346+
if err == nil || os.IsNotExist(err) {
347+
return nil
348+
}
349+
350+
return fmt.Errorf("failed to remove uncompressed-size sidecar for %s: %w", o.path, err)
351+
}
352+
301353
// fsPartUploader implements partUploader for local filesystem.
302354
// Embeds memPartUploader for concurrent-safe part collection,
303355
// then writes atomically on Complete.
@@ -312,7 +364,9 @@ func (u *fsPartUploader) Complete(_ context.Context) error {
312364
return fmt.Errorf("failed to create directory: %w", err)
313365
}
314366

315-
return os.WriteFile(u.fullPath, u.Assemble(), 0o644)
367+
_, err := replaceFile(u.fullPath, bytes.NewReader(u.Assemble()))
368+
369+
return err
316370
}
317371

318372
func (o *fsObject) OpenRangeReader(ctx context.Context, offsetU int64, length int64, frameTable *FrameTable) (_ RangeReader, _ Source, err error) {

0 commit comments

Comments
 (0)