|
@@ -12,6 +12,7 @@ import (
|
|
"fmt"
|
|
"fmt"
|
|
"io"
|
|
"io"
|
|
"strings"
|
|
"strings"
|
|
|
|
+ "sync"
|
|
)
|
|
)
|
|
|
|
|
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
|
@@ -33,7 +34,27 @@ const (
|
|
Future // Reserved for future definition.
|
|
Future // Reserved for future definition.
|
|
)
|
|
)
|
|
|
|
|
|
-var rander = rand.Reader // random function
|
|
|
|
|
|
+const randPoolSize = 16 * 16
|
|
|
|
+
|
|
|
|
+var (
|
|
|
|
+ rander = rand.Reader // random function
|
|
|
|
+ poolEnabled = false
|
|
|
|
+ poolMu sync.Mutex
|
|
|
|
+ poolPos = randPoolSize // protected with poolMu
|
|
|
|
+ pool [randPoolSize]byte // protected with poolMu
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+type invalidLengthError struct{ len int }
|
|
|
|
+
|
|
|
|
+func (err invalidLengthError) Error() string {
|
|
|
|
+ return fmt.Sprintf("invalid UUID length: %d", err.len)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
|
|
|
+func IsInvalidLengthError(err error) bool {
|
|
|
|
+ _, ok := err.(invalidLengthError)
|
|
|
|
+ return ok
|
|
|
|
+}
|
|
|
|
|
|
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
|
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
|
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
|
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
|
@@ -68,7 +89,7 @@ func Parse(s string) (UUID, error) {
|
|
}
|
|
}
|
|
return uuid, nil
|
|
return uuid, nil
|
|
default:
|
|
default:
|
|
- return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
|
|
|
|
|
+ return uuid, invalidLengthError{len(s)}
|
|
}
|
|
}
|
|
// s is now at least 36 bytes long
|
|
// s is now at least 36 bytes long
|
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
@@ -112,7 +133,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
|
}
|
|
}
|
|
return uuid, nil
|
|
return uuid, nil
|
|
default:
|
|
default:
|
|
- return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
|
|
|
|
|
+ return uuid, invalidLengthError{len(b)}
|
|
}
|
|
}
|
|
// s is now at least 36 bytes long
|
|
// s is now at least 36 bytes long
|
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
|
@@ -243,3 +264,31 @@ func SetRand(r io.Reader) {
|
|
}
|
|
}
|
|
rander = r
|
|
rander = r
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// EnableRandPool enables internal randomness pool used for Random
|
|
|
|
+// (Version 4) UUID generation. The pool contains random bytes read from
|
|
|
|
+// the random number generator on demand in batches. Enabling the pool
|
|
|
|
+// may improve the UUID generation throughput significantly.
|
|
|
|
+//
|
|
|
|
+// Since the pool is stored on the Go heap, this feature may be a bad fit
|
|
|
|
+// for security sensitive applications.
|
|
|
|
+//
|
|
|
|
+// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
|
|
|
+// only be called when there is no possibility that New or any other
|
|
|
|
+// UUID Version 4 generation function will be called concurrently.
|
|
|
|
+func EnableRandPool() {
|
|
|
|
+ poolEnabled = true
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// DisableRandPool disables the randomness pool if it was previously
|
|
|
|
+// enabled with EnableRandPool.
|
|
|
|
+//
|
|
|
|
+// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
|
|
|
+// only be called when there is no possibility that New or any other
|
|
|
|
+// UUID Version 4 generation function will be called concurrently.
|
|
|
|
+func DisableRandPool() {
|
|
|
|
+ poolEnabled = false
|
|
|
|
+ defer poolMu.Unlock()
|
|
|
|
+ poolMu.Lock()
|
|
|
|
+ poolPos = randPoolSize
|
|
|
|
+}
|