...
Source file src/cmd/go/internal/robustio/robustio_windows.go
1
2
3
4
5 package robustio
6
7 import (
8 "errors"
9 "internal/syscall/windows"
10 "io/ioutil"
11 "math/rand"
12 "os"
13 "syscall"
14 "time"
15 )
16
17 const arbitraryTimeout = 500 * time.Millisecond
18
19
20
21 func retry(f func() (err error, mayRetry bool)) error {
22 var (
23 bestErr error
24 lowestErrno syscall.Errno
25 start time.Time
26 nextSleep time.Duration = 1 * time.Millisecond
27 )
28 for {
29 err, mayRetry := f()
30 if err == nil || !mayRetry {
31 return err
32 }
33
34 var errno syscall.Errno
35 if errors.As(err, &errno) && (lowestErrno == 0 || errno < lowestErrno) {
36 bestErr = err
37 lowestErrno = errno
38 } else if bestErr == nil {
39 bestErr = err
40 }
41
42 if start.IsZero() {
43 start = time.Now()
44 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
45 break
46 }
47 time.Sleep(nextSleep)
48 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
49 }
50
51 return bestErr
52 }
53
54
55
56
57
58
59
60
61
62
63
64
65 func rename(oldpath, newpath string) (err error) {
66 return retry(func() (err error, mayRetry bool) {
67 err = os.Rename(oldpath, newpath)
68 return err, isEphemeralError(err)
69 })
70 }
71
72
73 func readFile(filename string) ([]byte, error) {
74 var b []byte
75 err := retry(func() (err error, mayRetry bool) {
76 b, err = ioutil.ReadFile(filename)
77
78
79
80
81 return err, isEphemeralError(err) && !errors.Is(err, syscall.ERROR_FILE_NOT_FOUND)
82 })
83 return b, err
84 }
85
86 func removeAll(path string) error {
87 return retry(func() (err error, mayRetry bool) {
88 err = os.RemoveAll(path)
89 return err, isEphemeralError(err)
90 })
91 }
92
93
94 func isEphemeralError(err error) bool {
95 var errno syscall.Errno
96 if errors.As(err, &errno) {
97 switch errno {
98 case syscall.ERROR_ACCESS_DENIED,
99 syscall.ERROR_FILE_NOT_FOUND,
100 windows.ERROR_SHARING_VIOLATION:
101 return true
102 }
103 }
104 return false
105 }
106
View as plain text