目的

  • 為處理唯一ID

紀錄

程式

generator.go

package snowflake

import (
	"sync"
	"time"
)

const (
	// 節點 ID 的位數 (0-1023)
	nodeBits  uint8 = 10
	// Index 的位數 (0-4095)
	indexBits  uint8 = 12
	// Index的最大值 用於檢測益出 (4095)
	indexMax  int64 = -1 ^ (-1 << indexBits)
	// 時間戳向左偏移量 (22位)
	timeShift = nodeBits + indexBits
	//	// 節點 ID 向左的偏移量 (10位)
	nodeShift = indexBits
	// 2018-12-03 12:00:08
	epoch int64 = 1543809608000
)

type NodeStruct struct {
	mutex sync.Mutex
	timestamp int64
	nodeType int64
	index int64
}

func Node(nodeType int64) *NodeStruct {
	// 返回 node 實例指針
	return &NodeStruct{
		timestamp: 0,
		nodeType: nodeType,
		index: 0,
	}
}

func (ns *NodeStruct) Generate() int {
	// 生成時加鎖
	ns.mutex.Lock()
	// 完成時解鎖
	defer ns.mutex.Unlock()

	// 取得當前時間戳
	now := time.Now().UnixNano() / 1e6
	if ns.timestamp == now{
		ns.index ++
		// 當前 index 用完
		if ns.index > indexMax {
			// 等待本毫秒结束
			for now <= ns.timestamp {
				now = time.Now().UnixNano() / 1e6
			}
		}
	} else {
		ns.index = 0
		ns.timestamp = now
	}

	// 位移運算生成 ID
	result := int( (now - epoch) << timeShift | (ns.nodeType << nodeShift) | (ns.index) )
	return result
}

func Inverse (nodeId int) *NodeStruct {
	// 返回 node 實例指針
	return &NodeStruct{
		timestamp: int64((nodeId >> timeShift) + int(epoch) ),
		nodeType: int64((nodeId >> indexBits) - (nodeId >> timeShift << nodeBits )),
		index: int64( (nodeId) - (nodeId >> indexBits << indexBits ) ),
	}
}