194 lines
6.3 KiB
Lua
194 lines
6.3 KiB
Lua
local bit = require("bit")
|
||
|
||
--创建一个雪花算法的类
|
||
local snowflake = {}
|
||
snowflake.__index = snowflake
|
||
|
||
local sequence = 0 --序列号
|
||
|
||
-- 基础配置
|
||
local twepoch = 1420041600 -- 时间戳起点(2015-01-01)
|
||
local workerIdBits = 5 -- 机器ID位数
|
||
local datacenterIdBits = 5 -- 数据中心ID位数
|
||
local timestampBits = 41 -- 时间戳位数
|
||
local sequenceBits = 12 -- 序列号位数
|
||
local max = math.pow(2, 32) --4294967296
|
||
|
||
local max_workerId = bit.lshift(1 , workerIdBits) - 1
|
||
local max_datacenterId = bit.lshift(1 , datacenterIdBits) - 1
|
||
|
||
-- 位移偏移量
|
||
local timestampShift = sequenceBits + workerIdBits + datacenterIdBits -- 时间戳左移22位
|
||
local datacenterIdShift = sequenceBits + datacenterIdBits -- 机器ID左移位数12位
|
||
local workerIdShift = sequenceBits -- 数据中心ID左移位数17位
|
||
-- 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
|
||
local sequenceMask = bit.lshift(1, sequenceBits) - 1;
|
||
--print("sequenceMask:", sequenceMask)
|
||
local lastTimestamp = -1; --上次生成ID的时间戳
|
||
|
||
--大数据数据左移
|
||
local function bit_lshift(x, n)
|
||
if n == 0 then return x end
|
||
return x * (2 ^ n)
|
||
end
|
||
|
||
--大数据数据右移
|
||
local function bit_rshift(x, n)
|
||
if n == 0 then return x end
|
||
x = x % 2^32 -- 处理负数问题
|
||
local res = x / 2^n
|
||
return res - res % 1 -- 取整操作,处理小数部分
|
||
end
|
||
|
||
-- 将一个大整数转换为32位整数数组
|
||
local function split_into_32bit_chunks(n)
|
||
local chunks = {}
|
||
while n > 0 do
|
||
table.insert(chunks, 1, n % 0x100000000) -- 取32位部分
|
||
n = math.floor(n / 0x100000000) -- 移除已处理的32位
|
||
end
|
||
return chunks
|
||
end
|
||
|
||
-- 执行按位与操作
|
||
local function bitwise_and(a, b)
|
||
local chunks_a = split_into_32bit_chunks(a)
|
||
local chunks_b = split_into_32bit_chunks(b)
|
||
local result = 0
|
||
local max_len = math.max(#chunks_a, #chunks_b)
|
||
print("max_len:", max_len)
|
||
for i = 0, max_len do
|
||
local chunk_a = chunks_a[i] or 0
|
||
local chunk_b = chunks_b[i] or 0
|
||
result = result * 0x100000000 + bit.band(chunk_a, chunk_b)
|
||
end
|
||
return result
|
||
end
|
||
|
||
local function bitwise_or(num1, num2)
|
||
local tmp1 = num1
|
||
local tmp2 = num2
|
||
local str = ""
|
||
while (tmp1 ~= 0 or tmp2 ~= 0)
|
||
do
|
||
local bit1 = tmp1 % 2
|
||
local bit2 = tmp2 % 2
|
||
if bit1 == 0 and bit2 == 0 then
|
||
str = "0" .. str
|
||
elseif bit1 == 1 or bit2 == 1 then
|
||
str = "1" .. str
|
||
else
|
||
str = "0" .. str
|
||
end
|
||
tmp1 = math.modf(tmp1 / 2)
|
||
tmp2 = math.modf(tmp2 / 2)
|
||
--print("tmp1:", tmp1)
|
||
--print("tmp2:", tmp2)
|
||
end
|
||
return tonumber(str, 2)
|
||
end
|
||
|
||
local function format_number(n, base)
|
||
local str = tostring(n)
|
||
--print("str:", str)
|
||
if base == 16 then -- 十六进制处理示例
|
||
return str:gsub("^0[xX]0*", "0x") -- 处理前导零和可能的'0x'
|
||
elseif base == 10 then -- 十进制处理示例
|
||
--print("value11:", str:gsub("^%-0*", ""))
|
||
--return str:gsub("^%-0*", "") -- 处理负数和前导零
|
||
return str:gsub("^0*([1-9]%d*)$", "%1")
|
||
else -- 其他基数可以按需添加处理逻辑
|
||
return str -- 或者根据需要返回其他格式化结果
|
||
end
|
||
end
|
||
|
||
function snowflake.int64_to_string(n)
|
||
local result = ""
|
||
local base = 100000000 -- 选择一个基数,例如10^8
|
||
while n > 0 do
|
||
local part = n % base
|
||
result = string.format("%08d", part) .. result
|
||
n = math.floor(n / base)
|
||
end
|
||
local value = format_number(result, 10)
|
||
--print("value:", value)
|
||
return value
|
||
end
|
||
|
||
--构造函数
|
||
function snowflake.new(workerId, datacenterId)
|
||
if workerId < 0 then workerId = 0 end
|
||
if workerId > max_workerId then workerId = max_workerId end
|
||
if datacenterId < 0 then datacenterId = 0 end
|
||
if datacenterId > max_datacenterId then datacenterId = max_datacenterId end
|
||
local instance = {workerId = workerId, datacenterId = datacenterId}
|
||
return setmetatable(instance, snowflake)
|
||
end
|
||
|
||
--获取当前时间戳(毫秒)
|
||
function snowflake:getCurrentTimestamp()
|
||
local timestamp = ngx.time()
|
||
return timestamp
|
||
end
|
||
|
||
--获取新的时间戳
|
||
function snowflake:getNextTimestamp(lastTimestamp)
|
||
local timestamp = math.floor(ngx.time());
|
||
while (timestamp <= lastTimestamp)
|
||
do
|
||
timestamp = math.floor(ngx.time());
|
||
end
|
||
return timestamp;
|
||
end
|
||
|
||
-- 雪花算法的实现
|
||
function snowflake:generateUniqueId()
|
||
--local curtime = ngx.time()
|
||
--print("current time: ", curtime)
|
||
local timestamp = self.getCurrentTimestamp() -- 当前时间戳(毫秒)
|
||
-- 如果是同一时间生成的,则进行毫秒内序列
|
||
if lastTimestamp == timestamp then
|
||
sequence = bit.band((sequence + 1), sequenceMask);
|
||
-- 毫秒内序列溢出
|
||
if sequence == 0 then
|
||
--阻塞到下一个毫秒,获得新的时间戳
|
||
timestamp = self.getNextTimestamp(lastTimestamp)
|
||
end
|
||
else
|
||
sequence = 0
|
||
end
|
||
lastTimestamp = timestamp;
|
||
--print("sequence:", sequence)
|
||
--print("lastTimestamp:", lastTimestamp)
|
||
|
||
local current_time = lastTimestamp - twepoch
|
||
--print("current time: ", current_time)
|
||
-- 位运算生成ID
|
||
--((timestamp - twepoch) << timestampLeftShift)
|
||
local timeNew = bit_lshift(current_time, timestampShift)
|
||
--print("timeNew: ", timeNew)
|
||
--(datacenterId << datacenterIdShift)
|
||
local centerIdNew = bit_lshift(self.datacenterId, datacenterIdShift)
|
||
--print("centerIdNew: ", centerIdNew)
|
||
--(workerId << workerIdShift)
|
||
local workerIdNew = bit_lshift(self.workerId, workerIdShift)
|
||
--print("workerIdNew: ", workerIdNew)
|
||
--((timestamp - twepoch) << timestampLeftShift)
|
||
--| (datacenterId << datacenterIdShift)
|
||
--| (workerId << workerIdShift) | sequence
|
||
--将相关数据值进行位或操作
|
||
local tmp1 = bitwise_or(timeNew, centerIdNew)
|
||
local tmp2 = bitwise_or(tmp1, workerIdNew)
|
||
local id = bitwise_or(tmp2, sequence)
|
||
return id
|
||
end
|
||
|
||
return snowflake
|
||
|
||
--使用方法示例
|
||
--local workerId = 0 -- 假设当前机器的ID是1,范围在[0, 31]之间
|
||
--local datacenterId = 0 -- 数据中心ID,范围在[0, 31]之间
|
||
--local test = snowflake.new(workerId, datacenterId)
|
||
--local id = test:generateUniqueId()-- 生成ID
|
||
--print("Generated ID:", test:int64_to_string(id))
|