taildrop: implement asynchronous file deletion (#9844)

File resumption requires keeping partial files around for some time,
but we must still eventually delete them if never resumed.
Thus, we implement asynchronous file deletion, which could
spawn a background goroutine to delete the files.

We also use the same mechanism for deleting files on Windows,
where a file can't be deleted if there is still an open file handle.
We can enqueue those with the asynchronous file deleter as well.

Updates tailscale/corp#14772

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai
2023-10-17 13:46:05 -07:00
committed by GitHub
parent 33bb2bbfe9
commit c2a551469c
10 changed files with 560 additions and 366 deletions

View File

@@ -19,7 +19,8 @@ func TestResume(t *testing.T) {
defer func() { blockSize = oldBlockSize }()
blockSize = 256
m := Manager{Logf: t.Logf, Dir: t.TempDir()}
m := ManagerOptions{Logf: t.Logf, Dir: t.TempDir()}.New()
defer m.Shutdown()
rn := rand.New(rand.NewSource(0))
want := make([]byte, 12345)
@@ -32,7 +33,7 @@ func TestResume(t *testing.T) {
})
must.Do(err)
must.Get(m.PutFile("", "foo", r, offset, -1))
got := must.Get(os.ReadFile(must.Get(m.joinDir("foo"))))
got := must.Get(os.ReadFile(must.Get(joinDir(m.opts.Dir, "foo"))))
if !bytes.Equal(got, want) {
t.Errorf("content mismatches")
}
@@ -54,7 +55,7 @@ func TestResume(t *testing.T) {
break
}
}
got := must.Get(os.ReadFile(must.Get(m.joinDir("foo"))))
got := must.Get(os.ReadFile(must.Get(joinDir(m.opts.Dir, "foo"))))
if !bytes.Equal(got, want) {
t.Errorf("content mismatches")
}