UUID(通用唯一识别码)是一种用于标识信息的方式,被广泛用于计算机系统。UUID的目的在于,确保在任何空间和时间中,赋予任何对象(或信息)的UUID都是唯一的,不需要一个中心机构来分配。
UUID的各个版本基于不同的信息来生成,它们的语义如下:
- UUID版本1(基于时间的UUID):这个版本的UUID是基于时间的,结合了计算机的MAC地址(或者其他硬件地址)和一个时间戳。由于时间戳的唯一性,保证了UUID的唯一性。这个版本的UUID可以揭示生成UUID的时间,以及生成UUID的机器的MAC地址。
-
UUID版本2(DCE安全的UUID):这个版本与版本1类似,也是基于时间的,但是会把时间戳的一部分替换为本地域的标识符,以及将生成器的主/辅标识符替换为用户或组ID。
-
UUID版本3(基于名字的UUID):这个版本的UUID是根据名字(通常是字符串)通过MD5散列算法计算出来的。相同的名字会生成相同的UUID,因此这个版本不适用于需要UUID唯一性的场合。
-
UUID版本4(随机UUID):这个版本的UUID是通过随机数生成的,它使用了随机数发生器或者伪随机数发生器。由于是完全随机的,因此这个版本的UUID具有很好的隐私保护特性。
-
UUID版本5(基于名字的UUID):这个版本与版本3类似,也是根据名字生成的,但是使用了SHA-1散列算法。与版本3一样,相同的名字会生成相同的UUID。
各个版本的UUID在不同场景下有不同的应用,比如版本1和版本2通常用于需要时间相关的唯一标识符的场合,版本3和版本5则用于从特定名字生成唯一标识符的场合,而版本4则用于需要随机唯一标识符的场合。在选择UUID版本时,需要根据实际应用的需求来决定使用哪一个版本。
go.uuid中的实现:
func (g *rfc4122Generator) NewV1() (UUID, error) {
u := UUID{}
timeNow, clockSeq, err := g.getClockSequence()
if err != nil {
return Nil, err
}
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
binary.BigEndian.PutUint16(u[8:], clockSeq)
hardwareAddr, err := g.getHardwareAddr()
if err != nil {
return Nil, err
}
copy(u[10:], hardwareAddr)
u.SetVersion(V1)
u.SetVariant(VariantRFC4122)
return u, nil
}
前10位是time和clock sequence。这里的clock sequence的实现是这样:
func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
var err error
g.clockSequenceOnce.Do(func() {
buf := make([]byte, 2)
if _, err = io.ReadFull(g.rand, buf); err != nil {
return
}
g.clockSequence = binary.BigEndian.Uint16(buf)
})
if err != nil {
return 0, 0, err
}
g.storageMutex.Lock()
defer g.storageMutex.Unlock()
timeNow := g.getEpoch()
// Clock didn't change since last UUID generation.
// Should increase clock sequence.
if timeNow <= g.lastTime {
g.clockSequence++
}
g.lastTime = timeNow
return timeNow, g.clockSequence, nil
}
最开始这里是读一个随机数,作为起始的sequence。
每次获取的时候,获取当前时间,如果等于上一次获取的时间,就会递增sequence。这里sequence可能wrap around,所以只是为了unique
然后g.getHardwareAddr读取当前mac地址
func defaultHWAddrFunc() (net.HardwareAddr, error) {
ifaces, err := net.Interfaces()
if err != nil {
return []byte{}, err
}
for _, iface := range ifaces {
if len(iface.HardwareAddr) >= 6 {
return iface.HardwareAddr, nil
}
}
return []byte{}, fmt.Errorf("uuid: no HW address found")
}
长度大于6的时候返回即可。这里感觉并不是非常的安全。
然后看了下c的libuuid,uuid_generate_time是类似的实现,不过这里的clock_seq是thread local的
看了下ob的uuid,在src/sql/engine/expr/ob_expr_uuid.cpp中,实现和go的uuid基本类似。
文章评论