taildrop: fix theoretical race condition in fileDeleter.Init (#9876)
It is possible that upon a cold-start, we enqueue a partial file for deletion that is resumed shortly after startup. If the file transfer happens to last longer than deleteDelay, we will delete the partial file, which is unfortunate. The client spent a long time uploading a file, only for it to be accidentally deleted. It's a very rare race, but also a frustrating one if it happens to manifest. Fix the code to only delete partial files that do not have an active puts against it. We also fix a minor bug in ResumeReader where we read b[:blockSize] instead of b[:cs.Size]. The former is the fixed size of 64KiB, while the latter is usually 64KiB, but may be less for the last block. Updates tailscale/corp#14772 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
+9
-10
@@ -112,16 +112,15 @@ func (m *Manager) DeleteFile(baseName string) error {
|
||||
err := os.Remove(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
err = redactError(err)
|
||||
// Put a retry loop around deletes on Windows. Windows
|
||||
// file descriptor closes are effectively asynchronous,
|
||||
// as a bunch of hooks run on/after close, and we can't
|
||||
// necessarily delete the file for a while after close,
|
||||
// as we need to wait for everybody to be done with
|
||||
// it. (on Windows, unlike Unix, a file can't be deleted
|
||||
// if it's open anywhere)
|
||||
// So try a few times but ultimately just leave a
|
||||
// "foo.jpg.deleted" marker file to note that it's
|
||||
// deleted and we clean it up later.
|
||||
// Put a retry loop around deletes on Windows.
|
||||
//
|
||||
// Windows file descriptor closes are effectively asynchronous,
|
||||
// as a bunch of hooks run on/after close,
|
||||
// and we can't necessarily delete the file for a while after close,
|
||||
// as we need to wait for everybody to be done with it.
|
||||
// On Windows, unlike Unix, a file can't be deleted if it's open anywhere.
|
||||
// So try a few times but ultimately just leave a "foo.jpg.deleted"
|
||||
// marker file to note that it's deleted and we clean it up later.
|
||||
if runtime.GOOS == "windows" {
|
||||
if bo == nil {
|
||||
bo = backoff.NewBackoff("delete-retry", logf, 1*time.Second)
|
||||
|
||||
Reference in New Issue
Block a user