feat(uuidv7): 添加 UUIDv7 生成器及解析功能
新增 UUIDv7 生成器实现,支持基于时间戳、节点 ID 和序列号的唯一标识符生成。 包含初始化、生成、解析以及错误处理等相关逻辑,并提供字节和字符串两种形式的 序列化与反序列化方法。同时添加了对生成器未初始化和节点 ID 超限的错误定义。
This commit is contained in:
13
serial_code/uuidv7/errors.go
Normal file
13
serial_code/uuidv7/errors.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package uuidv7
|
||||
|
||||
type UUIDv7GeneratorNotInitializedError struct{}
|
||||
|
||||
func (e *UUIDv7GeneratorNotInitializedError) Error() string {
|
||||
return "UUIDv7生成器尚未初始化"
|
||||
}
|
||||
|
||||
type UUIDv7NodeIDExceededError struct{}
|
||||
|
||||
func (e *UUIDv7NodeIDExceededError) Error() string {
|
||||
return "UUIDv7节点ID超出范围"
|
||||
}
|
225
serial_code/uuidv7/uuid.go
Normal file
225
serial_code/uuidv7/uuid.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package uuidv7
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
epoch = 1645566142222 // 自定义纪元:2022-02-22 22:22:22.222 UTC
|
||||
nodeBits = 5 // 主机编号容量为0~32
|
||||
sequenceBits = 18 // 每毫秒生成序列号最大为2^18-1,即262144个
|
||||
maxNodeID = (1 << nodeBits) - 1
|
||||
maxSequence = (1 << sequenceBits) - 1
|
||||
timestampShift = nodeBits + sequenceBits
|
||||
nodeShift = sequenceBits
|
||||
)
|
||||
|
||||
type UUIDv7Generator struct {
|
||||
locker sync.Mutex
|
||||
nodeID int64
|
||||
lastTime int64
|
||||
sequence int64
|
||||
}
|
||||
|
||||
type UUIDv7Components struct {
|
||||
Timestamp int64 // 毫秒时间戳(相对于自定义纪元)
|
||||
NodeID int64 // 5位节点ID
|
||||
Sequence int64 // 18位序列号
|
||||
Version int // 版本号(应为7)
|
||||
Variant int // 变体(应为2,表示10xx)
|
||||
RawBytes [16]byte // 原始字节
|
||||
}
|
||||
|
||||
var generatorInstance *UUIDv7Generator
|
||||
|
||||
// 获取UUIDv7生成器实例。如果实例尚未初始化,则返回错误。
|
||||
func Generator() (*UUIDv7Generator, error) {
|
||||
if generatorInstance == nil {
|
||||
return nil, &UUIDv7GeneratorNotInitializedError{}
|
||||
}
|
||||
return generatorInstance, nil
|
||||
}
|
||||
|
||||
// 指定一个主机编号,并完成UUIDv7生成器的初始化。如果主机编号超出范围,则返回错误。
|
||||
func Initialize(hostSerial int64) error {
|
||||
if hostSerial < 0 || hostSerial > maxNodeID {
|
||||
return &UUIDv7NodeIDExceededError{}
|
||||
}
|
||||
generatorInstance = &UUIDv7Generator{
|
||||
nodeID: hostSerial,
|
||||
lastTime: epoch,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取当前时间对应的新纪元毫秒时间戳。
|
||||
func (g *UUIDv7Generator) Now() int64 {
|
||||
return time.Now().UnixMilli() - epoch
|
||||
}
|
||||
|
||||
// 按顺序生成一个UUIDv7序号组件。
|
||||
func (g *UUIDv7Generator) Next() UUIDv7Components {
|
||||
g.locker.Lock()
|
||||
defer g.locker.Unlock()
|
||||
now := g.Now()
|
||||
if now < g.lastTime {
|
||||
// 防止时间回拔的情况,发生回拔时,直接使用上一次的时间戳
|
||||
now = g.lastTime
|
||||
}
|
||||
if now == g.lastTime {
|
||||
g.sequence++
|
||||
if g.sequence > maxSequence {
|
||||
time.Sleep(time.Millisecond)
|
||||
now = g.Now()
|
||||
g.sequence = 0
|
||||
}
|
||||
} else {
|
||||
g.sequence = 0
|
||||
}
|
||||
g.lastTime = now
|
||||
return UUIDv7Components{
|
||||
Timestamp: now,
|
||||
NodeID: g.nodeID,
|
||||
Sequence: g.sequence,
|
||||
Version: 7,
|
||||
Variant: 2,
|
||||
}
|
||||
}
|
||||
|
||||
// 读取随机字节
|
||||
func (c *UUIDv7Components) readRandom(bytes []byte) error {
|
||||
_, err := rand.Read(bytes)
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取UUIDv7原始字节数组
|
||||
func (c *UUIDv7Components) Bytes() [16]byte {
|
||||
// 构造 UUID
|
||||
var uuid [16]byte
|
||||
// 时间戳(48 位)
|
||||
timestamp := uint64(c.Timestamp) << timestampShift
|
||||
seqAndNode := (uint64(c.Sequence) << nodeShift) | uint64(c.NodeID)
|
||||
// 写入高位时间戳
|
||||
uuid[0] = byte(timestamp >> 56)
|
||||
uuid[1] = byte(timestamp >> 48)
|
||||
uuid[2] = byte(timestamp >> 40)
|
||||
uuid[3] = byte(timestamp >> 32)
|
||||
uuid[4] = byte(timestamp >> 24)
|
||||
uuid[5] = byte(timestamp >> 16)
|
||||
// 写入低位时间戳 + 版本号(4 位)
|
||||
uuid[6] = byte((timestamp >> 8) | 0x70) // version 7
|
||||
uuid[7] = byte(timestamp)
|
||||
// 写入 seq + node
|
||||
uuid[8] = byte((seqAndNode >> 16) | 0x80) // variant 10xx
|
||||
uuid[9] = byte(seqAndNode >> 8)
|
||||
uuid[10] = byte(seqAndNode)
|
||||
// 剩余位全为 0(可扩展为更多节点 ID 或随机数)
|
||||
randomBytes := make([]byte, 5)
|
||||
if err := c.readRandom(randomBytes); err != nil {
|
||||
// 如果随机数生成失败,使用时间相关值作为后备
|
||||
t := time.Now().UnixNano()
|
||||
randomBytes[0] = byte(t)
|
||||
randomBytes[1] = byte(t >> 8)
|
||||
randomBytes[2] = byte(t >> 16)
|
||||
randomBytes[3] = byte(t >> 24)
|
||||
randomBytes[4] = byte(c.Sequence)
|
||||
}
|
||||
copy(uuid[11:16], randomBytes)
|
||||
return uuid
|
||||
}
|
||||
|
||||
// 获取UUIDv7字符串
|
||||
func (c *UUIDv7Components) String() string {
|
||||
uuid := c.Bytes()
|
||||
return fmt.Sprintf("%x-%x-%x-%x-%x",
|
||||
uuid[0:4],
|
||||
uuid[4:6],
|
||||
uuid[6:8],
|
||||
uuid[8:10],
|
||||
uuid[10:16])
|
||||
}
|
||||
|
||||
// 对解析后的UUIDv7进行比较,按照时间戳、序列号、节点ID进行排序
|
||||
func CompareUUIDv7(a, b *UUIDv7Components) int {
|
||||
if a.Timestamp > b.Timestamp {
|
||||
return 1
|
||||
}
|
||||
if a.Timestamp < b.Timestamp {
|
||||
return -1
|
||||
}
|
||||
|
||||
if a.Sequence > b.Sequence {
|
||||
return 1
|
||||
}
|
||||
if a.Sequence < b.Sequence {
|
||||
return -1
|
||||
}
|
||||
|
||||
if a.NodeID > b.NodeID {
|
||||
return -1
|
||||
}
|
||||
if a.NodeID < b.NodeID {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// 与另一个UUIDv7进行比较,按照时间戳、序列号、节点ID进行排序
|
||||
func (c *UUIDv7Components) Compare(b *UUIDv7Components) int {
|
||||
return CompareUUIDv7(c, b)
|
||||
}
|
||||
|
||||
// ParseUUIDv7FromBytes 从字节数组解析 UUIDv7
|
||||
func ParseUUIDv7FromBytes(data [16]byte) (*UUIDv7Components, error) {
|
||||
// 提取时间戳(前48位)
|
||||
timestamp := (int64(data[0]) << 40) |
|
||||
(int64(data[1]) << 32) |
|
||||
(int64(data[2]) << 24) |
|
||||
(int64(data[3]) << 16) |
|
||||
(int64(data[4]) << 8) |
|
||||
int64(data[5])
|
||||
// 提取版本号(第6字节的高4位)
|
||||
version := int(data[6] >> 4)
|
||||
// 提取变体(第8字节的高2位)
|
||||
variant := int(data[8] >> 6)
|
||||
// 提取序列号和节点ID
|
||||
// 第8字节的低2位 + 第9字节 + 第10字节的高3位组成23位
|
||||
seqAndNode := (int64(data[8]&0x3F) << 16) | // 第8字节低6位
|
||||
(int64(data[9]) << 8) | // 第9字节
|
||||
int64(data[10]) // 第10字节
|
||||
// 分离序列号(高18位)和节点ID(低5位)
|
||||
sequence := seqAndNode >> 5
|
||||
nodeID := seqAndNode & 0x1F
|
||||
return &UUIDv7Components{
|
||||
Timestamp: timestamp,
|
||||
NodeID: nodeID,
|
||||
Sequence: sequence,
|
||||
Version: version,
|
||||
Variant: variant,
|
||||
RawBytes: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseUUIDv7FromString 从字符串解析 UUIDv7
|
||||
func ParseUUIDv7FromString(uuidStr string) (*UUIDv7Components, error) {
|
||||
// 移除连字符并验证长度
|
||||
cleanStr := strings.ReplaceAll(uuidStr, "-", "")
|
||||
if len(cleanStr) != 32 {
|
||||
return nil, fmt.Errorf("无效的UUIDv7字符串长度")
|
||||
}
|
||||
// 解码十六进制字符串
|
||||
bytes, err := hex.DecodeString(cleanStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无效的UUIDv7字符串格式: %v", err)
|
||||
}
|
||||
// 转换为数组
|
||||
var uuidBytes [16]byte
|
||||
copy(uuidBytes[:], bytes)
|
||||
return ParseUUIDv7FromBytes(uuidBytes)
|
||||
}
|
Reference in New Issue
Block a user