1
0
mirror of synced 2026-10-31 12:16:39 +08:00
Files
SnowFlake-IdGenerator/PHP/src/snowflake/snowflake.c
2021-04-07 11:51:02 +08:00

208 lines
5.6 KiB
C

#include <unistd.h>
#include <sys/time.h>
#include <stdlib.h>
#include "snowflake.h"
#include "spinlock.h"
#if defined(WIN32)
#include "windows.h"
#endif
static void EndOverCostAction(uint64_t useTimeTick, snowflake *flake);
static uint64_t NextOverCostId(snowflake *flake);
static uint64_t NextNormalId(snowflake *flake);
static uint64_t GetCurrentTimeTick(snowflake *flake);
static uint64_t GetNextTimeTick(snowflake *flake);
static uint64_t CalcId(snowflake *flake);
static uint64_t CalcTurnBackId(snowflake *flake);
int ncpu;
uint16_t spin = 2048;
uint32_t pid = 0;
void Config(snowflake *flake)
{
if (pid == 0)
{
pid = (uint32_t)getpid();
#if defined(WIN32)
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
ncpu = sysInfo.dwNumberOfProcessors;
#else
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
#endif
if (ncpu <= 0)
{
ncpu = 1;
}
}
flake->WorkerIdBitLength = flake->WorkerIdBitLength == 0 ? 6 : flake->WorkerIdBitLength;
flake->SeqBitLength = flake->SeqBitLength == 0 ? 6 : flake->SeqBitLength;
flake->MaxSeqNumber = flake->MaxSeqNumber > 0 ? flake->MaxSeqNumber : (-1L << flake->SeqBitLength) ^ -1L;
flake->BaseTime = flake->BaseTime != 0 ? flake->BaseTime : 1577808000000;
flake->_TimestampShift = (uint8_t)(flake->WorkerIdBitLength + flake->SeqBitLength);
flake->_CurrentSeqNumber = flake->MinSeqNumber;
return;
}
void inline EndOverCostAction(uint64_t useTimeTick, snowflake *flake)
{
if (flake->_TermIndex > 10000)
{
flake->_TermIndex = 0;
}
}
uint64_t inline NextOverCostId(snowflake *flake)
{
uint64_t currentTimeTick = GetCurrentTimeTick(flake);
if (currentTimeTick > flake->_LastTimeTick)
{
EndOverCostAction(currentTimeTick, flake);
flake->_LastTimeTick = currentTimeTick;
flake->_CurrentSeqNumber = flake->MinSeqNumber;
flake->_IsOverCost = 0;
flake->_OverCostCountInOneTerm = 0;
flake->_GenCountInOneTerm = 0;
return CalcId(flake);
}
if (flake->_OverCostCountInOneTerm > flake->TopOverCostCount)
{
EndOverCostAction(currentTimeTick, flake);
flake->_LastTimeTick = GetNextTimeTick(flake);
flake->_CurrentSeqNumber = flake->MinSeqNumber;
flake->_IsOverCost = 0;
flake->_OverCostCountInOneTerm = 0;
flake->_GenCountInOneTerm = 0;
return CalcId(flake);
}
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber)
{
flake->_LastTimeTick++;
flake->_CurrentSeqNumber = flake->MinSeqNumber;
flake->_IsOverCost = 1;
flake->_OverCostCountInOneTerm++;
flake->_GenCountInOneTerm++;
return CalcId(flake);
}
flake->_GenCountInOneTerm++;
return CalcId(flake);
}
uint64_t inline NextNormalId(snowflake *flake)
{
uint64_t currentTimeTick = GetCurrentTimeTick(flake);
if (currentTimeTick < flake->_LastTimeTick)
{
if (flake->_TurnBackTimeTick < 1)
{
flake->_TurnBackTimeTick = flake->_LastTimeTick - 1;
flake->_TurnBackIndex++;
if (flake->_TurnBackIndex > 4)
{
flake->_TurnBackIndex = 1;
}
}
return CalcTurnBackId(flake);
}
if (flake->_TurnBackTimeTick > 0)
{
flake->_TurnBackTimeTick = 0;
}
if (currentTimeTick > flake->_LastTimeTick)
{
flake->_LastTimeTick = currentTimeTick;
flake->_CurrentSeqNumber = flake->MinSeqNumber;
return CalcId(flake);
}
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber)
{
flake->_TermIndex++;
flake->_LastTimeTick++;
flake->_CurrentSeqNumber = flake->MinSeqNumber;
flake->_IsOverCost = 1;
flake->_OverCostCountInOneTerm = 1;
flake->_GenCountInOneTerm = 1;
return CalcId(flake);
}
return CalcId(flake);
}
uint64_t inline GetCurrentTimeTick(snowflake *flake)
{
struct timeval t;
gettimeofday(&t, NULL);
return (uint64_t)((t.tv_sec * 1000 + t.tv_usec / 1000) - flake->BaseTime);
}
uint64_t inline GetNextTimeTick(snowflake *flake)
{
uint64_t tempTimeTicker = GetCurrentTimeTick(flake);
while (tempTimeTicker <= flake->_LastTimeTick)
{
tempTimeTicker = GetCurrentTimeTick(flake);
}
return tempTimeTicker;
}
uint64_t inline CalcId(snowflake *flake)
{
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_CurrentSeqNumber);
flake->_CurrentSeqNumber++;
return result;
}
uint64_t inline CalcTurnBackId(snowflake *flake)
{
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_TurnBackTimeTick);
flake->_TurnBackTimeTick--;
return result;
}
uint64_t inline NextSonwId(snowflake *flake)
{
uint64_t currentTimeTick = GetCurrentTimeTick(flake);
if (flake->_LastTimeTick == currentTimeTick)
{
flake->_CurrentSeqNumber++;
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber)
{
flake->_CurrentSeqNumber = flake->MinSeqNumber;
currentTimeTick = GetNextTimeTick(flake);
}
}
else
{
flake->_CurrentSeqNumber = flake->MinSeqNumber;
}
flake->_LastTimeTick = currentTimeTick;
return (uint64_t)((currentTimeTick << flake->_TimestampShift) | (flake->WorkerId << flake->SeqBitLength) | flake->_CurrentSeqNumber);
}
uint64_t inline GetId(snowflake *flake)
{
return flake->Method == 1 ? (flake->_IsOverCost != 0 ? NextOverCostId(flake) : NextNormalId(flake)) : NextSonwId(flake);
}
uint64_t NextId(snowflake *flake)
{
spin_lock(&flake->_Lock, pid);
uint64_t id = GetId(flake);
spin_unlock(&flake->_Lock, pid);
return id;
}
uint64_t *NextNumId(snowflake *flake, uint32_t num)
{
uint64_t *arr = (uint64_t *)malloc(sizeof(uint64_t) * num);
spin_lock(&flake->_Lock, pid);
for (uint32_t i = 0; i < num; i++)
{
arr[i] = GetId(flake);
}
spin_unlock(&flake->_Lock, pid);
return arr;
}