AuthPlatform/src/share/snowflake.lua

194 lines
6.3 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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))