More than code

More Than Code
The efficiency of your iteration of reading, practicing and thinking decides your understanding of the world.
  1. 首页
  2. 其他
  3. 正文

UUID

2024年5月1日 298点热度 0人点赞 0条评论

UUID(通用唯一识别码)是一种用于标识信息的方式,被广泛用于计算机系统。UUID的目的在于,确保在任何空间和时间中,赋予任何对象(或信息)的UUID都是唯一的,不需要一个中心机构来分配。

UUID的各个版本基于不同的信息来生成,它们的语义如下:

  1. UUID版本1(基于时间的UUID):这个版本的UUID是基于时间的,结合了计算机的MAC地址(或者其他硬件地址)和一个时间戳。由于时间戳的唯一性,保证了UUID的唯一性。这个版本的UUID可以揭示生成UUID的时间,以及生成UUID的机器的MAC地址。

  2. UUID版本2(DCE安全的UUID):这个版本与版本1类似,也是基于时间的,但是会把时间戳的一部分替换为本地域的标识符,以及将生成器的主/辅标识符替换为用户或组ID。

  3. UUID版本3(基于名字的UUID):这个版本的UUID是根据名字(通常是字符串)通过MD5散列算法计算出来的。相同的名字会生成相同的UUID,因此这个版本不适用于需要UUID唯一性的场合。

  4. UUID版本4(随机UUID):这个版本的UUID是通过随机数生成的,它使用了随机数发生器或者伪随机数发生器。由于是完全随机的,因此这个版本的UUID具有很好的隐私保护特性。

  5. 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基本类似。

标签: 暂无
最后更新:2024年5月1日

sheep

think again

点赞
< 上一篇

文章评论

取消回复

COPYRIGHT © 2021 heavensheep.xyz. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS