// Newx returns a NONSTANDARD UUID(lower probability of conflict). func Newx() (uuid [16]byte) { var ( timestamp = uuidTimestamp() sequence uint32 ) gxMutex.Lock() // Lock switch { case timestamp > gxLastTimestamp: sequence = gxSequenceStart gxLastTimestamp = timestamp gxLastSequence = sequence gxMutex.Unlock() // Unlock case timestamp == gxLastTimestamp: sequence = (gxLastSequence + 1) & xSequenceMask if sequence == gxSequenceStart { timestamp = tillNext100nano(timestamp) gxLastTimestamp = timestamp } gxLastSequence = sequence gxMutex.Unlock() // Unlock default: // timestamp < xLastTimestamp gxSequenceStart = rand.Uint32() & xSequenceMask // NOTE sequence = gxSequenceStart gxLastTimestamp = timestamp gxLastSequence = sequence gxMutex.Unlock() // Unlock } // time_low uuid[0] = byte(timestamp >> 24) uuid[1] = byte(timestamp >> 16) uuid[2] = byte(timestamp >> 8) uuid[3] = byte(timestamp) // time_mid uuid[4] = byte(timestamp >> 40) uuid[5] = byte(timestamp >> 32) // time_hi_and_pid_low uuid[6] = byte(timestamp >> 52) uuid[7] = byte(timestamp>>48) << 4 uuid[7] |= pid & 0x0F // pid, 4bits // clk_seq_hi_pid uuid[8] = byte(sequence>>8) & 0x3F uuid[8] |= (pid << 2) & 0xC0 // // pid, 2bits // clk_seq_low uuid[9] = byte(sequence) // node copy(uuid[10:], xNode) return }
// New returns a STANDARD version 1 UUID. func New() (uuid [16]byte) { var ( timestamp = uuidTimestamp() sequence uint32 ) gMutex.Lock() // Lock switch { case timestamp > gLastTimestamp: sequence = gSequenceStart gLastTimestamp = timestamp gLastSequence = sequence gMutex.Unlock() // Unlock case timestamp == gLastTimestamp: sequence = (gLastSequence + 1) & sequenceMask if sequence == gSequenceStart { timestamp = tillNext100nano(timestamp) gLastTimestamp = timestamp } gLastSequence = sequence gMutex.Unlock() // Unlock default: // timestamp < lastTimestamp gSequenceStart = rand.Uint32() & sequenceMask // NOTE sequence = gSequenceStart gLastTimestamp = timestamp gLastSequence = sequence gMutex.Unlock() // Unlock } // time_low uuid[0] = byte(timestamp >> 24) uuid[1] = byte(timestamp >> 16) uuid[2] = byte(timestamp >> 8) uuid[3] = byte(timestamp) // time_mid uuid[4] = byte(timestamp >> 40) uuid[5] = byte(timestamp >> 32) // time_hi_and_version uuid[6] = byte(timestamp>>56) & 0x0F uuid[6] |= 0x10 // version 1, 4bits uuid[7] = byte(timestamp >> 48) // clk_seq_hi_res uuid[8] = byte(sequence>>8) & 0x3F uuid[8] |= 0x80 // variant, 2bits // clk_seq_low uuid[9] = byte(sequence) // node copy(uuid[10:], node) return }
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ var pid = byte(hash(uint64(os.Getpid()))) // 6-bit hash of os.Getpid(), read only. // hash uint64 to a 6-bit integer value. func hash(x uint64) uint64 { return (x ^ x>>6 ^ x>>12 ^ x>>18 ^ x>>24 ^ x>>30 ^ x>>36 ^ x>>42 ^ x>>48 ^ x>>54 ^ x>>60) & 0x3f } var xNode = internal.MAC[:] // read only. const xSequenceMask uint32 = 0x3FFF // 14bits var ( gxMutex sync.Mutex gxSequenceStart uint32 = rand.Uint32() & xSequenceMask gxLastTimestamp int64 = -1 gxLastSequence uint32 = gxSequenceStart ) // Newx returns a NONSTANDARD UUID(lower probability of conflict). func Newx() (uuid [16]byte) { var ( timestamp = uuidTimestamp() sequence uint32 ) gxMutex.Lock() // Lock switch { case timestamp > gxLastTimestamp: sequence = gxSequenceStart
// New returns a unique 32-byte url-safe string. func New() string { var ( timeNow = time.Now() timeNowUnix = timeNow.Unix() timestamp = unix100nano(timeNow) sequence uint32 saltShouldUpdate = false saltSequence uint32 ) gMutex.Lock() // Lock switch { case timestamp > gLastTimestamp: sequence = gSequenceStart gLastTimestamp = timestamp gLastSequence = sequence case timestamp == gLastTimestamp: sequence = (gLastSequence + 1) & sequenceMask if sequence == gSequenceStart { timestamp = tillNext100nano(timestamp) gLastTimestamp = timestamp } gLastSequence = sequence default: gSequenceStart = rand.Uint32() & sequenceMask // NOTE sequence = gSequenceStart gLastTimestamp = timestamp gLastSequence = sequence } if timeNowUnix >= gSaltLastUpdateTimestamp+saltUpdateInterval { saltShouldUpdate = true gSaltLastUpdateTimestamp = timeNowUnix } gSaltSequence++ saltSequence = gSaltSequence gMutex.Unlock() // Unlock // 56bits unix100ns + 12bits pid + 12bits sequence + 48bits node + 64bits hashsum var idx [24]byte // time_low idx[0] = byte(timestamp >> 24) idx[1] = byte(timestamp >> 16) idx[2] = byte(timestamp >> 8) idx[3] = byte(timestamp) // time_mid idx[4] = byte(timestamp >> 40) idx[5] = byte(timestamp >> 32) // time_hi_and_pid_low idx[6] = byte(timestamp >> 48) idx[7] = byte(pid) // clk_seq_hi_pid idx[8] = byte(sequence>>8) & 0x0f idx[8] |= byte(pid>>8) << 4 // clk_seq_low idx[9] = byte(sequence) // node copy(idx[10:], node) // hashsum if saltShouldUpdate { rand.Read(gSalt) copy(idx[16:], gSalt) } else { var src [8 + 4 + saltLen]byte // 8+4+43==55 src[0] = byte(timestamp >> 56) src[1] = byte(timestamp >> 48) src[2] = byte(timestamp >> 40) src[3] = byte(timestamp >> 32) src[4] = byte(timestamp >> 24) src[5] = byte(timestamp >> 16) src[6] = byte(timestamp >> 8) src[7] = byte(timestamp) src[8] = byte(saltSequence >> 24) src[9] = byte(saltSequence >> 16) src[10] = byte(saltSequence >> 8) src[11] = byte(saltSequence) copy(src[12:], gSalt) hashsum := sha1.Sum(src[:]) copy(idx[16:], hashsum[:]) } id := make([]byte, 32) base64.URLEncoding.Encode(id, idx[:]) return string(id) }
} var node = internal.MAC[:] // read only const ( sequenceMask = 0xfff // 12bits saltLen = 43 // see New(), 8+4+43==55<56, Best performance for sha1. saltUpdateInterval = 3600 // seconds ) var ( gSalt = make([]byte, saltLen) gMutex sync.Mutex // protect following gSequenceStart uint32 = rand.Uint32() & sequenceMask gLastTimestamp int64 = -1 gLastSequence uint32 = gSequenceStart gSaltLastUpdateTimestamp int64 = -saltUpdateInterval gSaltSequence uint32 = rand.Uint32() ) // New returns a unique 32-byte url-safe string. func New() string { var ( timeNow = time.Now() timeNowUnix = timeNow.Unix() timestamp = unix100nano(timeNow) sequence uint32