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
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/internal/robustio/robustio_flaky.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/internal/robustio/robustio_flaky.go
new file mode 100644 (file)
index 0000000..e0bf5b9
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows darwin
+
+package robustio
+
+import (
+       "io/ioutil"
+       "math/rand"
+       "os"
+       "syscall"
+       "time"
+)
+
+const arbitraryTimeout = 500 * time.Millisecond
+
+const ERROR_SHARING_VIOLATION = 32
+
+// retry retries ephemeral errors from f up to an arbitrary timeout
+// to work around filesystem flakiness on Windows and Darwin.
+func retry(f func() (err error, mayRetry bool)) error {
+       var (
+               bestErr     error
+               lowestErrno syscall.Errno
+               start       time.Time
+               nextSleep   time.Duration = 1 * time.Millisecond
+       )
+       for {
+               err, mayRetry := f()
+               if err == nil || !mayRetry {
+                       return err
+               }
+
+               if errno, ok := err.(syscall.Errno); ok && (lowestErrno == 0 || errno < lowestErrno) {
+                       bestErr = err
+                       lowestErrno = errno
+               } else if bestErr == nil {
+                       bestErr = err
+               }
+
+               if start.IsZero() {
+                       start = time.Now()
+               } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
+                       break
+               }
+               time.Sleep(nextSleep)
+               nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
+       }
+
+       return bestErr
+}
+
+// rename is like os.Rename, but retries ephemeral errors.
+//
+// On windows it wraps os.Rename, which (as of 2019-06-04) uses MoveFileEx with
+// MOVEFILE_REPLACE_EXISTING.
+//
+// Windows also provides a different system call, ReplaceFile,
+// that provides similar semantics, but perhaps preserves more metadata. (The
+// documentation on the differences between the two is very sparse.)
+//
+// Empirical error rates with MoveFileEx are lower under modest concurrency, so
+// for now we're sticking with what the os package already provides.
+func rename(oldpath, newpath string) (err error) {
+       return retry(func() (err error, mayRetry bool) {
+               err = os.Rename(oldpath, newpath)
+               return err, isEphemeralError(err)
+       })
+}
+
+// readFile is like ioutil.ReadFile, but retries ephemeral errors.
+func readFile(filename string) ([]byte, error) {
+       var b []byte
+       err := retry(func() (err error, mayRetry bool) {
+               b, err = ioutil.ReadFile(filename)
+
+               // Unlike in rename, we do not retry errFileNotFound here: it can occur
+               // as a spurious error, but the file may also genuinely not exist, so the
+               // increase in robustness is probably not worth the extra latency.
+
+               return err, isEphemeralError(err) && err != errFileNotFound
+       })
+       return b, err
+}
+
+func removeAll(path string) error {
+       return retry(func() (err error, mayRetry bool) {
+               err = os.RemoveAll(path)
+               return err, isEphemeralError(err)
+       })
+}