You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
2.5 KiB
Lua

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

socket = require "socket"
math = require "math"
bit = require "bit"
-- 开始时间截 (2015-01-01)
twepoch = 1420041600000
-- 机器id所占的位数
workerIdBits = 5
-- 数据标识id所占的位数
datacenterIdBits = 5
-- 序列在id中占的位数
sequenceBits = 12
-- 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
maxWorkerId = bit.lshift(1 , workerIdBits)-1
-- 支持的最大数据标识id结果是31
maxDatacenterId = bit.lshift(1 , datacenterIdBits)-1
-- 机器ID向左移12位
workerIdShift = sequenceBits
-- 数据标识id向左移17位(12+5)
datacenterIdShift = sequenceBits + workerIdBits
-- 时间截向左移22位(5+5+12)
timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits
-- 生成序列的掩码这里为4095 (0b111111111111=0xfff=4095)
sequenceMask = bit.lshift(1 , sequenceBits) -1
-- 工作机器ID(0~31)
workerId=1
-- 数据中心ID(0~31)
datacenterId=1
-- 毫秒内序列(0~4095)
sequence = 0
-- 上次生成ID的时间截
lastTimestamp = -1
local _M = {}
function _M.SnowflakeIdWorker (workerIds, datacenterIds)
if (workerIds > maxWorkerId or workerIds < 0)
then
return -1
end
if (datacenterIds > maxDatacenterId or datacenterIds < 0)
then
return -1
end
workerId=workerIds
datacenterId=datacenterIds
end
local function tilNextMillis(lastTimestamp)
local timestamp = math.floor(socket.gettime() * 1000 )
while (timestamp <= lastTimestamp)
do
timestamp = math.floor(socket.gettime() * 1000 )
end
return timestamp
end
function _M.nextId ()
local timestamp = math.floor(socket.gettime() * 1000 )
-- 如果当前时间小于上一次ID生成的时间戳说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp)
then
return -1
end
-- 如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp)
then
sequence = bit.band((sequence + 1), sequenceMask)
-- 毫秒内序列溢出
if (sequence == 0)
then
--阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp)
end
else
sequence = 0
end
lastTimestamp = timestamp
cmd =("sh ./id.sh " .. timestamp .. '\t' ..twepoch .. '\t'.. timestampLeftShift .. '\t'.. datacenterId .. '\t'.. datacenterIdShift .. '\t'.. workerId .. '\t'.. workerIdShift .. '\t'.. sequence)
id = os.execute(cmd)
return id
end
return _M