golang-uuidv1

源码解读 github.com/satori/go.uuid

// NewV1 returns UUID based on current timestamp and MAC address.
func (g *generator) NewV1() UUID {
u := UUID{}

timeNow, clockSeq, hardwareAddr := g.getStorage()
//前32bits time-low
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
// 16bits time-mid
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
// o Set the 12 least significant bits (bits zero through 11) of the
// time_hi_and_version field equal to bits 48 through 59 from the
// timestamp in the same order of significance.

// o Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number
// corresponding to the UUID version being created, as shown in the
// table above.
// 4bits(version) + 12bits(time_hi)
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
// 8bits clock-seq-and-reserved + 8bits clock-seq-low
binary.BigEndian.PutUint16(u[8:], clockSeq)
//48bits node
copy(u[10:], hardwareAddr)
// 设置版本
u.SetVersion(V1)
// 设置变体
u.SetVariant(VariantRFC4122)

return u
}

BigEndian 这里使用大端序,可能会出问题

获取时钟,当期时间 和 mac 地址

// Returns UUID v1/v2 storage state.
// Returns epoch timestamp, clock sequence, and hardware address.
func (g *generator) getStorage() (uint64, uint16, []byte) {
//sync.Once确保mac地址,和clockSequence只会初始化一次
g.storageOnce.Do(g.initStorage)

g.storageMutex.Lock()
defer g.storageMutex.Unlock()

timeNow := epochFunc()
// Clock changed backwards since last UUID generation.
// Should increase clock sequence.
// 如果系统时间出现回退或者,在100ns内多次产生uuid.高并发的时候需要clockSequence区分周期
if timeNow <= g.lastTime {
g.clockSequence++
}
g.lastTime = timeNow

return timeNow, g.clockSequence, g.hardwareAddr[:]
}

初始化时钟和 mac 地址

func (g *generator) initStorage() {
g.initClockSequence()
g.initHardwareAddr()
}

func (g *generator) initClockSequence() {
buf := make([]byte, 2)
g.safeRandom(buf)
// 获取随机数作为初始 clockSequence
g.clockSequence = binary.BigEndian.Uint16(buf)
}

func (g *generator) initHardwareAddr() {
interfaces, err := net.Interfaces()
if err == nil {
for _, iface := range interfaces {
fmt.Printf("iface.HardwareAddr %v \n", iface)
if len(iface.HardwareAddr) >= 6 {
// 找到mac地址
copy(g.hardwareAddr[:], iface.HardwareAddr)
return
}
}
}

// Initialize hardwareAddr randomly in case
// of real network interfaces absence
// 没mac地址就先随机
g.safeRandom(g.hardwareAddr[:])

// Set multicast bit as recommended in RFC 4122
// For systems with no IEEE address, a randomly or pseudo-randomly
// generated value may be used; see Section 4.5. The multicast bit must
// be set in such addresses, in order that they will never conflict with
// addresses obtained from network cards.

g.hardwareAddr[0] |= 0x01
}

当前时间.

  • 初始时间- UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
  • 当期时间戳(100ns 为单位)

const epochStart = 122192928000000000)

// Returns difference in 100-nanosecond intervals between
// UUID epoch (October 15, 1582) and current time.
// This is default epoch calculation function.
func unixTimeFunc() uint64 {
return epochStart + uint64(time.Now().UnixNano()/100)
}

总结

v1 生成 uuid 的基础数据是 100ns 基本的时间戳 + mac 地址(没有的情况为随机)
一般加入 timestamp 1.是为了时间维度 2.是为了便于 sort
但是 uuid 规范的的顺序是 time-low - time-mid - 4bits(version) + 12bits(time_hi)
所以是不能根据 uuid 来 sort 的