Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / internal / robustio / robustio_flaky.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build windows darwin
6
7 package robustio
8
9 import (
10         "io/ioutil"
11         "math/rand"
12         "os"
13         "syscall"
14         "time"
15 )
16
17 const arbitraryTimeout = 500 * time.Millisecond
18
19 const ERROR_SHARING_VIOLATION = 32
20
21 // retry retries ephemeral errors from f up to an arbitrary timeout
22 // to work around filesystem flakiness on Windows and Darwin.
23 func retry(f func() (err error, mayRetry bool)) error {
24         var (
25                 bestErr     error
26                 lowestErrno syscall.Errno
27                 start       time.Time
28                 nextSleep   time.Duration = 1 * time.Millisecond
29         )
30         for {
31                 err, mayRetry := f()
32                 if err == nil || !mayRetry {
33                         return err
34                 }
35
36                 if errno, ok := err.(syscall.Errno); ok && (lowestErrno == 0 || errno < lowestErrno) {
37                         bestErr = err
38                         lowestErrno = errno
39                 } else if bestErr == nil {
40                         bestErr = err
41                 }
42
43                 if start.IsZero() {
44                         start = time.Now()
45                 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
46                         break
47                 }
48                 time.Sleep(nextSleep)
49                 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
50         }
51
52         return bestErr
53 }
54
55 // rename is like os.Rename, but retries ephemeral errors.
56 //
57 // On windows it wraps os.Rename, which (as of 2019-06-04) uses MoveFileEx with
58 // MOVEFILE_REPLACE_EXISTING.
59 //
60 // Windows also provides a different system call, ReplaceFile,
61 // that provides similar semantics, but perhaps preserves more metadata. (The
62 // documentation on the differences between the two is very sparse.)
63 //
64 // Empirical error rates with MoveFileEx are lower under modest concurrency, so
65 // for now we're sticking with what the os package already provides.
66 func rename(oldpath, newpath string) (err error) {
67         return retry(func() (err error, mayRetry bool) {
68                 err = os.Rename(oldpath, newpath)
69                 return err, isEphemeralError(err)
70         })
71 }
72
73 // readFile is like ioutil.ReadFile, but retries ephemeral errors.
74 func readFile(filename string) ([]byte, error) {
75         var b []byte
76         err := retry(func() (err error, mayRetry bool) {
77                 b, err = ioutil.ReadFile(filename)
78
79                 // Unlike in rename, we do not retry errFileNotFound here: it can occur
80                 // as a spurious error, but the file may also genuinely not exist, so the
81                 // increase in robustness is probably not worth the extra latency.
82
83                 return err, isEphemeralError(err) && err != errFileNotFound
84         })
85         return b, err
86 }
87
88 func removeAll(path string) error {
89         return retry(func() (err error, mayRetry bool) {
90                 err = os.RemoveAll(path)
91                 return err, isEphemeralError(err)
92         })
93 }