uuid,全称Universally Unique IDentifier,是一种id生成方式,我们使用它来生成一唯一的id. 同时,它也被称为guid. uuid有若干生成方法,本文介绍的是一种基于时间的方法(也就是version 1).协议是rfc4122. 在java中,它是系统内置的class.而在c++中,我们想要实现,其实也不困难.

如rfc4122中所示,uuid是一个长为128bit的结构如下的一串数字.

_0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          time_low                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       time_mid                |         time_hi_and_version   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         node (2-5)                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中time是指UTC 1582年10月15日00:00:00 开始到如今的,以100纳秒为单位的时间数,它是一个60bit长的一个值,所以被存到了几段地方.

clk_seq按情况而定,若可以读状态,那么clk_seq是上个状态的clk_seq+1,否则是随机出来的一个0x3FFF范围中的数字.

node是自定义的一个顺序.

然后一路拼接,得到两个uint64_t类型的数据.输出结果若用string表示,格式应该是这样的:

UUID                   = time-low "-" time-mid "-"
                               time-high-and-version "-"
                               clock-seq-and-reserved
                               clock-seq-low "-" node
time-low               = 4hexOctet
time-mid               = 2hexOctet
time-high-and-version  = 2hexOctet
clock-seq-and-reserved = hexOctet
clock-seq-low          = hexOctet
node                   = 6hexOctet
hexOctet               = hexDigit hexDigit
hexDigit =
            "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" /
            "a" / "b" / "c" / "d" / "e" / "f" /
            "A" / "B" / "C" / "D" / "E" / "F"

一个简单例子如下:

f81d4fae-7dec-11d0-a765-00a0c91e6bf6

rfc4122给了个官方实现示例,我也写了个c++版本的简易生成器,里面有些代码还是值得商榷的,比如clk_seq我是直接random的.其实应该检查状态的.代码在osx和centos 64上都编译没有问题.

在java/scala中,若要读取uuid,一般我用fromString.

scala> java.util.UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
res0: java.util.UUID = f81d4fae-7dec-11d0-a765-00a0c91e6bf6

需要注意的是,uuid中的timestamp和普通的java.util.date中的timestamp单位是不一样的,我们已经说过,uuid中是UTC 1582年10月15日00:00:00至今的100纳秒数,而date中的是UTC1970年1月1日00:00:00至今的毫秒数.我们从uuid中获取ts方法应该是这样的:

scala> val uuid = java.util.UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
uuid: java.util.UUID = f81d4fae-7dec-11d0-a765-00a0c91e6bf6

scala> val ts = uuid.timestamp
ts: Long = 130742845922168750

scala> val ts4j = ( ts - 0x01b21dd213814000L ) / 10000
ts4j: Long = 854991792216

scala> val jdate = new java.util.Date(ts4j)
jdate: java.util.Date = Mon Feb 03 12:43:12 EST 1997

References


Yu

Ideals are like the stars: we never reach them, but like the mariners of the sea, we chart our course by them.

Leave a Reply

Your email address will not be published. Required fields are marked *