123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- //go:build linux
- package overlayutils // import "github.com/docker/docker/daemon/graphdriver/overlayutils"
- import (
- "crypto/rand"
- "encoding/base32"
- "fmt"
- "io"
- "os"
- "syscall"
- "time"
- "github.com/containerd/log"
- "golang.org/x/sys/unix"
- )
- // GenerateID creates a new random string identifier with the given length
- func GenerateID(l int, logger *log.Entry) string {
- const (
- // ensures we backoff for less than 450ms total. Use the following to
- // select new value, in units of 10ms:
- // n*(n+1)/2 = d -> n^2 + n - 2d -> n = (sqrt(8d + 1) - 1)/2
- maxretries = 9
- backoff = time.Millisecond * 10
- )
- var (
- totalBackoff time.Duration
- count int
- retries int
- size = (l*5 + 7) / 8
- u = make([]byte, size)
- )
- // TODO: Include time component, counter component, random component
- for {
- // This should never block but the read may fail. Because of this,
- // we just try to read the random number generator until we get
- // something. This is a very rare condition but may happen.
- b := time.Duration(retries) * backoff
- time.Sleep(b)
- totalBackoff += b
- n, err := io.ReadFull(rand.Reader, u[count:])
- if err != nil {
- if retryOnError(err) && retries < maxretries {
- count += n
- retries++
- logger.Errorf("error generating version 4 uuid, retrying: %v", err)
- continue
- }
- // Any other errors represent a system problem. What did someone
- // do to /dev/urandom?
- panic(fmt.Errorf("error reading random number generator, retried for %v: %v", totalBackoff.String(), err))
- }
- break
- }
- s := base32.StdEncoding.EncodeToString(u)
- return s[:l]
- }
- // retryOnError tries to detect whether or not retrying would be fruitful.
- func retryOnError(err error) bool {
- switch err := err.(type) {
- case *os.PathError:
- return retryOnError(err.Err) // unpack the target error
- case syscall.Errno:
- if err == unix.EPERM {
- // EPERM represents an entropy pool exhaustion, a condition under
- // which we backoff and retry.
- return true
- }
- }
- return false
- }
|