mirror of
https://github.com/google/uuid.git
synced 2024-11-24 08:32:23 +02:00
fix: Monotonicity in UUIDv7 (#150)
* Monotonicity in UUIDv7 * fix Monotonicity * fix comment * Monotonicity 2 * lock * fix comment * fix comment
This commit is contained in:
parent
c58770eb49
commit
a2b2b32373
23
uuid_test.go
23
uuid_test.go
@ -825,7 +825,7 @@ func TestVersion6(t *testing.T) {
|
||||
func TestVersion7(t *testing.T) {
|
||||
SetRand(nil)
|
||||
m := make(map[string]bool)
|
||||
for x := 1; x < 32; x++ {
|
||||
for x := 1; x < 128; x++ {
|
||||
uuid, err := NewV7()
|
||||
if err != nil {
|
||||
t.Fatalf("could not create UUID: %v", err)
|
||||
@ -874,8 +874,7 @@ func TestVersion7_pooled(t *testing.T) {
|
||||
func TestVersion7FromReader(t *testing.T) {
|
||||
myString := "8059ddhdle77cb52"
|
||||
r := bytes.NewReader([]byte(myString))
|
||||
r2 := bytes.NewReader([]byte(myString))
|
||||
uuid1, err := NewV7FromReader(r)
|
||||
_, err := NewV7FromReader(r)
|
||||
if err != nil {
|
||||
t.Errorf("failed generating UUID from a reader")
|
||||
}
|
||||
@ -883,11 +882,17 @@ func TestVersion7FromReader(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Errorf("expecting an error as reader has no more bytes. Got uuid. NewV7FromReader may not be using the provided reader")
|
||||
}
|
||||
uuid3, err := NewV7FromReader(r2)
|
||||
if err != nil {
|
||||
t.Errorf("failed generating UUID from a reader")
|
||||
}
|
||||
if uuid1 != uuid3 {
|
||||
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid3)
|
||||
}
|
||||
|
||||
func TestVersion7Monotonicity(t *testing.T) {
|
||||
length := 10000
|
||||
u1 := Must(NewV7()).String()
|
||||
for i := 0; i < length; i++ {
|
||||
u2 := Must(NewV7()).String()
|
||||
if u2 <= u1 {
|
||||
t.Errorf("monotonicity failed at #%d: %s(next) < %s(before)", i, u2, u1)
|
||||
break
|
||||
}
|
||||
u1 = u2
|
||||
}
|
||||
}
|
||||
|
39
version7.go
39
version7.go
@ -44,7 +44,7 @@ func NewV7FromReader(r io.Reader) (UUID, error) {
|
||||
|
||||
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
|
||||
// uuid[8] already has the right version number (Variant is 10)
|
||||
// see function NewV7 and NewV7FromReader
|
||||
// see function NewV7 and NewV7FromReader
|
||||
func makeV7(uuid []byte) {
|
||||
/*
|
||||
0 1 2 3
|
||||
@ -52,7 +52,7 @@ func makeV7(uuid []byte) {
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| unix_ts_ms |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| unix_ts_ms | ver | rand_a |
|
||||
| unix_ts_ms | ver | rand_a (12 bit seq) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|var| rand_b |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@ -61,7 +61,7 @@ func makeV7(uuid []byte) {
|
||||
*/
|
||||
_ = uuid[15] // bounds check
|
||||
|
||||
t := timeNow().UnixMilli()
|
||||
t, s := getV7Time()
|
||||
|
||||
uuid[0] = byte(t >> 40)
|
||||
uuid[1] = byte(t >> 32)
|
||||
@ -70,6 +70,35 @@ func makeV7(uuid []byte) {
|
||||
uuid[4] = byte(t >> 8)
|
||||
uuid[5] = byte(t)
|
||||
|
||||
uuid[6] = 0x70 | (uuid[6] & 0x0F)
|
||||
// uuid[8] has already has right version
|
||||
uuid[6] = 0x70 | (0x0F & byte(s>>8))
|
||||
uuid[7] = byte(s)
|
||||
}
|
||||
|
||||
// lastV7time is the last last time we returned stored as:
|
||||
//
|
||||
// 52 bits of time in milliseconds since epoch
|
||||
// 12 bits of (fractional nanoseconds) >> 8
|
||||
var lastV7time int64
|
||||
|
||||
const nanoPerMilli = 1000000
|
||||
|
||||
// getV7Time returns the time in milliseconds and nanoseconds / 256.
|
||||
// The returned (milli << 12 + seq) is guarenteed to be greater than
|
||||
// (milli << 12 + seq) returned by any previous call to getV7Time.
|
||||
func getV7Time() (milli, seq int64) {
|
||||
timeMu.Lock()
|
||||
defer timeMu.Unlock()
|
||||
|
||||
nano := timeNow().UnixNano()
|
||||
milli = nano / nanoPerMilli
|
||||
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
|
||||
seq = (nano - milli*nanoPerMilli) >> 8
|
||||
now := milli<<12 + seq
|
||||
if now <= lastV7time {
|
||||
now = lastV7time + 1
|
||||
milli = now >> 12
|
||||
seq = now & 0xfff
|
||||
}
|
||||
lastV7time = now
|
||||
return milli, seq
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user