@@ -64,12 +64,17 @@ namespace Yitter.OrgSystem.TestA | |||||
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)] | [DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)] | ||||
public static extern long NextId(); | public static extern long NextId(); | ||||
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)] | |||||
public static extern void SetWorkerId(int workerId); | |||||
private static void CallDll() | private static void CallDll() | ||||
{ | { | ||||
int i = 0; | int i = 0; | ||||
long id = 0; | long id = 0; | ||||
DateTime start = DateTime.Now; | DateTime start = DateTime.Now; | ||||
SetWorkerId(1); | |||||
while (i < 50000) | while (i < 50000) | ||||
{ | { | ||||
id = NextId(); | id = NextId(); | ||||
@@ -1,6 +1,8 @@ | |||||
# idgenerator | # idgenerator | ||||
something is going on. | |||||
## 编译说明 | |||||
using c | |||||
1.默认是 Linux 环境,用 CMake。 | |||||
2.如果是 Windows 环境,要用 Cygwin 或 MinGW。 | |||||
@@ -0,0 +1,258 @@ | |||||
## Ignore Visual Studio temporary files, build results, and | |||||
## files generated by popular Visual Studio add-ons. | |||||
# User-specific files | |||||
*.suo | |||||
*.user | |||||
*.userosscache | |||||
*.sln.docstates | |||||
*.editorconfig | |||||
# User-specific files (MonoDevelop/Xamarin Studio) | |||||
*.userprefs | |||||
# Build results | |||||
[Dd]ebug/ | |||||
[Dd]ebugPublic/ | |||||
[Rr]elease/ | |||||
[Rr]eleases/ | |||||
x64/ | |||||
x86/ | |||||
bld/ | |||||
[Bb]in/ | |||||
[Oo]bj/ | |||||
[Ll]og/ | |||||
# Visual Studio 2015 cache/options directory | |||||
**/.vs/ | |||||
# Uncomment if you have tasks that create the project's static files in wwwroot | |||||
#wwwroot/ | |||||
# MSTest test Results | |||||
[Tt]est[Rr]esult*/ | |||||
[Bb]uild[Ll]og.* | |||||
# NUNIT | |||||
*.VisualState.xml | |||||
TestResult.xml | |||||
# Build Results of an ATL Project | |||||
[Dd]ebugPS/ | |||||
[Rr]eleasePS/ | |||||
# DNX | |||||
project.lock.json | |||||
artifacts/ | |||||
*_i.c | |||||
*_p.c | |||||
*_i.h | |||||
*.ilk | |||||
*.meta | |||||
*.obj | |||||
*.pch | |||||
*.pdb | |||||
*.pgc | |||||
*.pgd | |||||
*.rsp | |||||
*.sbr | |||||
*.tlb | |||||
*.tli | |||||
*.tlh | |||||
*.tmp | |||||
*.tmp_proj | |||||
*.log | |||||
*.vspscc | |||||
*.vssscc | |||||
.builds | |||||
*.pidb | |||||
*.svclog | |||||
*.scc | |||||
# Chutzpah Test files | |||||
_Chutzpah* | |||||
# Visual C++ cache files | |||||
ipch/ | |||||
*.aps | |||||
*.ncb | |||||
*.opendb | |||||
*.opensdf | |||||
*.sdf | |||||
*.cachefile | |||||
*.VC.db | |||||
*.VC.VC.opendb | |||||
# Visual Studio profiler | |||||
*.psess | |||||
*.vsp | |||||
*.vspx | |||||
*.sap | |||||
# TFS 2012 Local Workspace | |||||
$tf/ | |||||
# Guidance Automation Toolkit | |||||
*.gpState | |||||
# ReSharper is a .NET coding add-in | |||||
_ReSharper*/ | |||||
*.[Rr]e[Ss]harper | |||||
*.DotSettings.user | |||||
# JustCode is a .NET coding add-in | |||||
.JustCode | |||||
# TeamCity is a build add-in | |||||
_TeamCity* | |||||
# DotCover is a Code Coverage Tool | |||||
*.dotCover | |||||
# NCrunch | |||||
_NCrunch_* | |||||
.*crunch*.local.xml | |||||
nCrunchTemp_* | |||||
# MightyMoose | |||||
*.mm.* | |||||
AutoTest.Net/ | |||||
# Web workbench (sass) | |||||
.sass-cache/ | |||||
# Installshield output folder | |||||
[Ee]xpress/ | |||||
# DocProject is a documentation generator add-in | |||||
DocProject/buildhelp/ | |||||
DocProject/Help/*.HxT | |||||
DocProject/Help/*.HxC | |||||
DocProject/Help/*.hhc | |||||
DocProject/Help/*.hhk | |||||
DocProject/Help/*.hhp | |||||
DocProject/Help/Html2 | |||||
DocProject/Help/html | |||||
# Click-Once directory | |||||
publish/ | |||||
# Publish Web Output | |||||
*.[Pp]ublish.xml | |||||
*.azurePubxml | |||||
# TODO: Comment the next line if you want to checkin your web deploy settings | |||||
# but database connection strings (with potential passwords) will be unencrypted | |||||
*.pubxml | |||||
*.publishproj | |||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to | |||||
# checkin your Azure Web App publish settings, but sensitive information contained | |||||
# in these scripts will be unencrypted | |||||
PublishScripts/ | |||||
# NuGet Packages | |||||
*.nupkg | |||||
*.snupkg | |||||
# The packages folder can be ignored because of Package Restore | |||||
**/packages/* | |||||
# except build/, which is used as an MSBuild target. | |||||
!**/packages/build/ | |||||
# Uncomment if necessary however generally it will be regenerated when needed | |||||
#!**/packages/repositories.config | |||||
# NuGet v3's project.json files produces more ignoreable files | |||||
*.nuget.props | |||||
*.nuget.targets | |||||
# Microsoft Azure Build Output | |||||
csx/ | |||||
*.build.csdef | |||||
# Microsoft Azure Emulator | |||||
ecf/ | |||||
rcf/ | |||||
# Windows Store app package directories and files | |||||
AppPackages/ | |||||
BundleArtifacts/ | |||||
Package.StoreAssociation.xml | |||||
_pkginfo.txt | |||||
# Visual Studio cache files | |||||
# files ending in .cache can be ignored | |||||
*.[Cc]ache | |||||
# but keep track of directories ending in .cache | |||||
!*.[Cc]ache/ | |||||
# Others | |||||
ClientBin/ | |||||
~$* | |||||
*~ | |||||
*.dbmdl | |||||
*.dbproj.schemaview | |||||
*.pfx | |||||
*.publishsettings | |||||
node_modules/ | |||||
orleans.codegen.cs | |||||
# Since there are multiple workflows, uncomment next line to ignore bower_components | |||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) | |||||
#bower_components/ | |||||
# RIA/Silverlight projects | |||||
Generated_Code/ | |||||
# Backup & report files from converting an old project file | |||||
# to a newer Visual Studio version. Backup files are not needed, | |||||
# because we have git ;-) | |||||
_UpgradeReport_Files/ | |||||
Backup*/ | |||||
UpgradeLog*.XML | |||||
UpgradeLog*.htm | |||||
# SQL Server files | |||||
*.mdf | |||||
*.ldf | |||||
# Business Intelligence projects | |||||
*.rdl.data | |||||
*.bim.layout | |||||
*.bim_*.settings | |||||
# Microsoft Fakes | |||||
FakesAssemblies/ | |||||
# GhostDoc plugin setting file | |||||
*.GhostDoc.xml | |||||
# Node.js Tools for Visual Studio | |||||
.ntvs_analysis.dat | |||||
# Visual Studio 6 build log | |||||
*.plg | |||||
# Visual Studio 6 workspace options file | |||||
*.opt | |||||
# Visual Studio LightSwitch build output | |||||
**/*.HTMLClient/GeneratedArtifacts | |||||
**/*.DesktopClient/GeneratedArtifacts | |||||
**/*.DesktopClient/ModelManifest.xml | |||||
**/*.Server/GeneratedArtifacts | |||||
**/*.Server/ModelManifest.xml | |||||
_Pvt_Extensions | |||||
# Paket dependency manager | |||||
.paket/paket.exe | |||||
paket-files/ | |||||
# FAKE - F# Make | |||||
.fake/ | |||||
# JetBrains Rider | |||||
.idea/ | |||||
*.sln.iml | |||||
target/ | |||||
cmake-build*/ | |||||
# macOS | |||||
.DS_Store |
@@ -0,0 +1,27 @@ | |||||
cmake_minimum_required(VERSION 3.17) | |||||
project(YitIdGen) | |||||
set(CMAKE_C_STANDARD 11) | |||||
#set(CMAKE_BUILD_TYPE DEBUG) | |||||
#set(CMAKE_BUILD_TYPE RELEASE) | |||||
aux_source_directory(. DIR_SRCS) | |||||
add_subdirectory(idgen) | |||||
##编译动态库 | |||||
#set(LIB_SRC YitIdHelper.h YitIdHelper.c) | |||||
#add_library(YitIdGenLib SHARED ${LIB_SRC}) | |||||
#target_link_libraries(YitIdGenLib idgen) | |||||
#set_target_properties(YitIdGenLib PROPERTIES | |||||
# LINKER_LANGUAGE C | |||||
# OUTPUT_NAME "yitidgenc" | |||||
# PREFIX "") | |||||
##编译执行文件 | |||||
set(LIB_SRC YitIdHelper.h YitIdHelper.c) | |||||
add_library(YitIdHelper ${LIB_SRC}) | |||||
add_executable(YitIdGen main.c) | |||||
target_link_libraries(YitIdHelper idgen) | |||||
target_link_libraries(YitIdGen YitIdHelper) | |||||
@@ -0,0 +1,22 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include <stdlib.h> | |||||
#include <stdint.h> | |||||
#include "YitIdHelper.h" | |||||
#include "idgen/IdGenerator.h" | |||||
extern void SetIdGenerator(IdGeneratorOptions options) { | |||||
SetOptions(options); | |||||
} | |||||
extern void SetWorker(uint32_t workerId) { | |||||
IdGeneratorOptions options = BuildIdGenOptions(workerId); | |||||
SetIdGenerator(options); | |||||
} | |||||
extern uint64_t NextId() { | |||||
return GetIdGenInstance()->NextId(); | |||||
} | |||||
@@ -0,0 +1,15 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#pragma once | |||||
#include "idgen/IdGenOptions.h" | |||||
__declspec(dllexport) void __stdcall SetIdGenerator(IdGeneratorOptions options); | |||||
__declspec(dllexport) void __stdcall SetWorker(uint32_t workerId); | |||||
__declspec(dllexport) uint64_t __stdcall NextId(); | |||||
@@ -0,0 +1,7 @@ | |||||
aux_source_directory(. DIR_LIB_SRCS) | |||||
add_library(idgen ${DIR_LIB_SRCS}) | |||||
#SET(LIB_SRC ../YitIdHelper.h ../YitIdHelper.c) | |||||
#add_library(YitIdGenLib SHARED ${LIB_SRC}) | |||||
#target_link_libraries(YitIdGenLib IdGen) | |||||
@@ -0,0 +1,34 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include "IdGenOptions.h" | |||||
extern IdGeneratorOptions BuildIdGenOptions(uint32_t workerId) { | |||||
IdGeneratorOptions options; | |||||
options.Method = 1; | |||||
options.BaseTime = 1582136402000; | |||||
options.WorkerId = workerId; | |||||
options.WorkerIdBitLength = 6; | |||||
options.SeqBitLength = 6; | |||||
options.MaxSeqNumber = 0; | |||||
options.MinSeqNumber = 5; | |||||
options.TopOverCostCount = 2000; | |||||
return options; | |||||
// IdGeneratorOptions *options = (IdGeneratorOptions *) malloc(sizeof(IdGeneratorOptions)); | |||||
// | |||||
// options->Method = 1; | |||||
// options->BaseTime = 1582136402000; | |||||
// options->WorkerId = workerId; | |||||
// options->WorkerIdBitLength = 6; | |||||
// options->SeqBitLength = 6; | |||||
// options->MaxSeqNumber = 63; | |||||
// options->MinSeqNumber = 5; | |||||
// options->TopOverCostCount = 2000; | |||||
// | |||||
// return options; | |||||
} |
@@ -0,0 +1,31 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#pragma once | |||||
#include <stdint.h> | |||||
typedef struct IdGenOptions { | |||||
/// 雪花计算方法,(1-漂移算法|2-传统算法),默认1 | |||||
uint8_t Method; | |||||
/// 基础时间(ms单位),不能超过当前系统时间 | |||||
uint64_t BaseTime; | |||||
/// 机器码,与 WorkerIdBitLength 有关系 | |||||
uint32_t WorkerId; | |||||
/// 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22) | |||||
uint8_t WorkerIdBitLength; | |||||
/// 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22) | |||||
uint8_t SeqBitLength; | |||||
/// 最大序列数(含),(由 SeqBitLength 计算的最大值) | |||||
uint32_t MaxSeqNumber; | |||||
/// 最小序列数(含),默认5,不小于5,不大于 MaxSeqNumber | |||||
uint32_t MinSeqNumber; | |||||
/// 最大漂移次数(含),默认2000,推荐范围 500-20000(与计算能力有关) | |||||
uint32_t TopOverCostCount; | |||||
} IdGeneratorOptions; | |||||
extern IdGeneratorOptions BuildIdGenOptions(uint32_t workerId); | |||||
@@ -0,0 +1,107 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <malloc.h> | |||||
#include <pthread.h> | |||||
#include <errno.h> | |||||
#include <unistd.h> | |||||
#include "IdGenerator.h" | |||||
static inline uint64_t WorkerM1Id() { | |||||
return WorkerM1NextId(_idGenerator->Worker); | |||||
} | |||||
static inline uint64_t WorkerM2Id() { | |||||
return WorkerM2NextId(_idGenerator->Worker); | |||||
} | |||||
extern IdGenerator *GetIdGenInstance() { | |||||
if (_idGenerator != NULL) | |||||
return _idGenerator; | |||||
else { | |||||
_idGenerator = (IdGenerator *) malloc(sizeof(IdGenerator)); | |||||
_idGenerator->Worker = NewSnowFlakeWorker(); | |||||
return _idGenerator; | |||||
} | |||||
} | |||||
extern void SetOptions(IdGeneratorOptions options) { | |||||
if (GetIdGenInstance() == NULL) { | |||||
exit(1); | |||||
} | |||||
// BaseTime | |||||
if (options.BaseTime == 0) { | |||||
_idGenerator->Worker->BaseTime = 1582136402000; | |||||
} else if (options.BaseTime < 631123200000 || options.BaseTime > GetCurrentTime()) { | |||||
perror("BaseTime error."); | |||||
exit(1); | |||||
} else { | |||||
_idGenerator->Worker->BaseTime = options.BaseTime; | |||||
} | |||||
// WorkerIdBitLength | |||||
if (options.WorkerIdBitLength <= 0) { | |||||
perror("WorkerIdBitLength error.(range:[1, 21])"); | |||||
exit(1); | |||||
} | |||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) { | |||||
perror("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||||
exit(1); | |||||
} else { | |||||
// _idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength; | |||||
_idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength <= 0 ? 6 : options.WorkerIdBitLength; | |||||
} | |||||
// WorkerId | |||||
uint32_t maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1; | |||||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) { | |||||
perror("WorkerId error. (range:[0, {2^options.WorkerIdBitLength-1]}"); | |||||
exit(1); | |||||
} else { | |||||
_idGenerator->Worker->WorkerId = options.WorkerId; | |||||
} | |||||
// SeqBitLength | |||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) { | |||||
perror("SeqBitLength error. (range:[2, 21])"); | |||||
exit(1); | |||||
} else { | |||||
// _idGenerator->Worker->SeqBitLength = options.SeqBitLength; | |||||
_idGenerator->Worker->SeqBitLength = options.SeqBitLength <= 0 ? 6 : options.SeqBitLength; | |||||
} | |||||
// MaxSeqNumber | |||||
uint32_t maxSeqNumber = (1 << options.SeqBitLength) - 1; | |||||
if (options.MaxSeqNumber > maxSeqNumber) { | |||||
perror("MaxSeqNumber error. (range:[1, {2^options.SeqBitLength-1}]"); | |||||
exit(1); | |||||
} else { | |||||
_idGenerator->Worker->MaxSeqNumber = options.MaxSeqNumber <= 0 ? maxSeqNumber : options.MaxSeqNumber; | |||||
} | |||||
// MinSeqNumber | |||||
if (options.MinSeqNumber > maxSeqNumber || options.MinSeqNumber < 5) { | |||||
perror("MinSeqNumber error. (range:[5, {options.MinSeqNumber}]"); | |||||
exit(1); | |||||
} else { | |||||
_idGenerator->Worker->MinSeqNumber = options.MinSeqNumber <= 0 ? 5 : options.MinSeqNumber; | |||||
} | |||||
_idGenerator->Worker->TopOverCostCount = options.TopOverCostCount <= 0 ? 2000 : options.TopOverCostCount; | |||||
_idGenerator->Worker->_TimestampShift = options.WorkerIdBitLength + options.SeqBitLength; | |||||
_idGenerator->Worker->_CurrentSeqNumber = options.MinSeqNumber; | |||||
_idGenerator->Worker->Method = options.Method; | |||||
if (options.Method == 2) { | |||||
_idGenerator->NextId = WorkerM2Id; | |||||
} else { | |||||
_idGenerator->NextId = WorkerM1Id; | |||||
sleep(1); | |||||
} | |||||
} | |||||
@@ -0,0 +1,30 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#pragma once | |||||
#include <stdio.h> | |||||
#include <malloc.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <errno.h> | |||||
#include "IdGenOptions.h" | |||||
#include "SnowWorkerM1.h" | |||||
#include "SnowWorkerM2.h" | |||||
typedef struct IdGenerator { | |||||
SnowFlakeWorker *Worker; | |||||
uint64_t (*NextId)(); | |||||
} IdGenerator; | |||||
static IdGenerator *_idGenerator = NULL; | |||||
extern IdGenerator *GetIdGenInstance(); | |||||
extern void SetOptions(IdGeneratorOptions options); | |||||
@@ -0,0 +1,154 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 代码翻译:amuluowin | |||||
* 代码修订:yitter | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include <malloc.h> | |||||
#include <stdlib.h> | |||||
#include <stdbool.h> | |||||
#include <sys/time.h> | |||||
#include "SnowWorkerM1.h" | |||||
pthread_mutex_t ThreadMutex = PTHREAD_MUTEX_INITIALIZER; | |||||
static void EndOverCostAction(uint64_t useTimeTick, SnowFlakeWorker *worker); | |||||
static uint64_t NextOverCostId(SnowFlakeWorker *worker); | |||||
static uint64_t NextNormalId(SnowFlakeWorker *worker); | |||||
static uint64_t CalcId(SnowFlakeWorker *worker); | |||||
static uint64_t CalcTurnBackId(SnowFlakeWorker *worker); | |||||
static inline void EndOverCostAction(uint64_t useTimeTick, SnowFlakeWorker *worker) { | |||||
if (worker->_TermIndex > 10000) { | |||||
worker->_TermIndex = 0; | |||||
} | |||||
} | |||||
static inline uint64_t NextOverCostId(SnowFlakeWorker *worker) { | |||||
uint64_t currentTimeTick = GetCurrentTimeTick(worker); | |||||
if (currentTimeTick > worker->_LastTimeTick) { | |||||
EndOverCostAction(currentTimeTick, worker); | |||||
worker->_LastTimeTick = currentTimeTick; | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
worker->_IsOverCost = false; | |||||
worker->_OverCostCountInOneTerm = 0; | |||||
worker->_GenCountInOneTerm = 0; | |||||
return CalcId(worker); | |||||
} | |||||
if (worker->_OverCostCountInOneTerm > worker->TopOverCostCount) { | |||||
EndOverCostAction(currentTimeTick, worker); | |||||
worker->_LastTimeTick = GetNextTimeTick(worker); | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
worker->_IsOverCost = false; | |||||
worker->_OverCostCountInOneTerm = 0; | |||||
worker->_GenCountInOneTerm = 0; | |||||
return CalcId(worker); | |||||
} | |||||
if (worker->_CurrentSeqNumber > worker->MaxSeqNumber) { | |||||
worker->_LastTimeTick++; | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
worker->_IsOverCost = true; | |||||
worker->_OverCostCountInOneTerm++; | |||||
worker->_GenCountInOneTerm++; | |||||
return CalcId(worker); | |||||
} | |||||
worker->_GenCountInOneTerm++; | |||||
return CalcId(worker); | |||||
} | |||||
static inline uint64_t NextNormalId(SnowFlakeWorker *worker) { | |||||
uint64_t currentTimeTick = GetCurrentTimeTick(worker); | |||||
if (currentTimeTick < worker->_LastTimeTick) { | |||||
if (worker->_TurnBackTimeTick < 1) { | |||||
worker->_TurnBackTimeTick = worker->_LastTimeTick - 1; | |||||
worker->_TurnBackIndex++; | |||||
if (worker->_TurnBackIndex > 4) { | |||||
worker->_TurnBackIndex = 1; | |||||
} | |||||
} | |||||
return CalcTurnBackId(worker); | |||||
} | |||||
if (worker->_TurnBackTimeTick > 0) { | |||||
worker->_TurnBackTimeTick = 0; | |||||
} | |||||
if (currentTimeTick > worker->_LastTimeTick) { | |||||
worker->_LastTimeTick = currentTimeTick; | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
return CalcId(worker); | |||||
} | |||||
if (worker->_CurrentSeqNumber > worker->MaxSeqNumber) { | |||||
worker->_TermIndex++; | |||||
worker->_LastTimeTick++; | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
worker->_IsOverCost = true; | |||||
worker->_OverCostCountInOneTerm = 1; | |||||
worker->_GenCountInOneTerm = 1; | |||||
return CalcId(worker); | |||||
} | |||||
return CalcId(worker); | |||||
} | |||||
static inline uint64_t CalcId(SnowFlakeWorker *worker) { | |||||
uint64_t result = (worker->_LastTimeTick << worker->_TimestampShift) | (worker->WorkerId << worker->SeqBitLength) | | |||||
(worker->_CurrentSeqNumber); | |||||
worker->_CurrentSeqNumber++; | |||||
return result; | |||||
} | |||||
static inline uint64_t CalcTurnBackId(SnowFlakeWorker *worker) { | |||||
uint64_t result = (worker->_LastTimeTick << worker->_TimestampShift) | (worker->WorkerId << worker->SeqBitLength) | | |||||
(worker->_TurnBackTimeTick); | |||||
worker->_TurnBackTimeTick--; | |||||
return result; | |||||
} | |||||
extern SnowFlakeWorker *NewSnowFlakeWorker() { | |||||
SnowFlakeWorker *worker = (SnowFlakeWorker *) malloc(sizeof(SnowFlakeWorker)); | |||||
worker->_IsOverCost = false; | |||||
return worker; | |||||
} | |||||
extern uint64_t WorkerM1NextId(SnowFlakeWorker *worker) { | |||||
pthread_mutex_lock(&ThreadMutex); | |||||
uint64_t id = worker->_IsOverCost ? NextOverCostId(worker) : NextNormalId(worker); | |||||
pthread_mutex_unlock(&ThreadMutex); | |||||
return id; | |||||
} | |||||
extern uint64_t GetCurrentTimeTick(SnowFlakeWorker *worker) { | |||||
static struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
return (uint64_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000 - worker->BaseTime); | |||||
} | |||||
extern uint64_t GetCurrentTime() { | |||||
static struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
return (uint64_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000); | |||||
//static struct timeb t1; | |||||
// ftime(&t1); | |||||
// return (uint64_t) ((t1.time * 1000 + t1.millitm)); | |||||
} | |||||
extern uint64_t GetCurrentMicroTime() { | |||||
static struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
return (uint64_t)(tv.tv_sec * 1000000 + tv.tv_usec); | |||||
} | |||||
extern uint64_t GetNextTimeTick(SnowFlakeWorker *worker) { | |||||
uint64_t tempTimeTicker = GetCurrentTimeTick(worker); | |||||
while (tempTimeTicker <= worker->_LastTimeTick) { | |||||
tempTimeTicker = GetCurrentTimeTick(worker); | |||||
} | |||||
return tempTimeTicker; | |||||
} |
@@ -0,0 +1,53 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 代码翻译:amuluowin | |||||
* 代码修订:yitter | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#pragma once | |||||
#include <stdlib.h> | |||||
#include <stdint.h> | |||||
#include <sys/timeb.h> | |||||
#include <pthread.h> | |||||
#include <stdbool.h> | |||||
#include "IdGenOptions.h" | |||||
extern pthread_mutex_t ThreadMutex; | |||||
typedef struct SnowFlakeWorker { | |||||
uint8_t Method; | |||||
uint64_t BaseTime; | |||||
uint32_t WorkerId; | |||||
uint8_t WorkerIdBitLength; | |||||
uint8_t SeqBitLength; | |||||
uint32_t MaxSeqNumber; | |||||
uint32_t MinSeqNumber; | |||||
uint32_t TopOverCostCount; | |||||
uint8_t _TimestampShift; | |||||
uint32_t _CurrentSeqNumber; | |||||
int64_t _LastTimeTick; | |||||
int64_t _TurnBackTimeTick; | |||||
uint8_t _TurnBackIndex; | |||||
bool _IsOverCost; | |||||
uint32_t _OverCostCountInOneTerm; | |||||
uint32_t _GenCountInOneTerm; | |||||
uint32_t _TermIndex; | |||||
} SnowFlakeWorker; | |||||
extern SnowFlakeWorker *NewSnowFlakeWorker(); | |||||
extern uint64_t WorkerM1NextId(SnowFlakeWorker *worker); | |||||
extern uint64_t GetCurrentTimeTick(SnowFlakeWorker *worker); | |||||
extern uint64_t GetNextTimeTick(SnowFlakeWorker *worker); | |||||
extern uint64_t GetCurrentTime(); | |||||
extern uint64_t GetCurrentMicroTime(); | |||||
@@ -0,0 +1,30 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 代码翻译:amuluowin | |||||
* 代码修订:yitter | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include <malloc.h> | |||||
#include <stdlib.h> | |||||
#include <pthread.h> | |||||
#include "SnowWorkerM2.h" | |||||
extern uint64_t WorkerM2NextId(SnowFlakeWorker *worker) { | |||||
pthread_mutex_lock(&ThreadMutex); | |||||
uint64_t currentTimeTick = GetCurrentTimeTick(worker); | |||||
if (worker->_LastTimeTick == currentTimeTick) { | |||||
worker->_CurrentSeqNumber = (++worker->_CurrentSeqNumber) & worker->MaxSeqNumber; | |||||
if (worker->_CurrentSeqNumber == 0) { | |||||
currentTimeTick = GetNextTimeTick(worker); | |||||
} | |||||
} else { | |||||
worker->_CurrentSeqNumber = worker->MinSeqNumber; | |||||
} | |||||
worker->_LastTimeTick = currentTimeTick; | |||||
uint64_t id = (uint64_t) ((currentTimeTick << worker->_TimestampShift) | | |||||
(worker->WorkerId << worker->SeqBitLength) | | |||||
worker->_CurrentSeqNumber); | |||||
pthread_mutex_unlock(&ThreadMutex); | |||||
return id; | |||||
} |
@@ -0,0 +1,13 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 代码翻译:amuluowin | |||||
* 代码修订:yitter | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#pragma once | |||||
#include <stdlib.h> | |||||
#include "SnowWorkerM1.h" | |||||
extern uint64_t WorkerM2NextId(SnowFlakeWorker *worker); |
@@ -0,0 +1,67 @@ | |||||
/* | |||||
* 版权属于:yitter(yitter@126.com) | |||||
* 代码翻译:amuluowin | |||||
* 代码修订:yitter | |||||
* 开源地址:https://gitee.com/yitter/idgenerator | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <sys/timeb.h> | |||||
#include <pthread.h> | |||||
#include <unistd.h> | |||||
#include <stdbool.h> | |||||
#include "idgen/SnowWorkerM1.h" | |||||
#include "idgen/IdGenerator.h" | |||||
#include "YitIdHelper.h" | |||||
const int GenIdCount = 50000; | |||||
const bool multiThread = false; | |||||
const int threadCount = 50; | |||||
const int method = 1; | |||||
void RunMultiThread() { | |||||
//int64_t start = GetCurrentMicroTime(); | |||||
for (int i = 0; i < GenIdCount / threadCount; i++) { | |||||
int64_t id = NextId(); | |||||
printf("生成ID: %ld\n", id); | |||||
} | |||||
int64_t end = GetCurrentMicroTime(); | |||||
//printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start)); | |||||
} | |||||
void RunSingle() { | |||||
int64_t start = GetCurrentMicroTime(); | |||||
for (int i = 0; i < GenIdCount; i++) { | |||||
int64_t id = NextId(); | |||||
// printf("生成ID: %ld\n", id); | |||||
} | |||||
int64_t end = GetCurrentMicroTime(); | |||||
printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start)); | |||||
} | |||||
int main() { | |||||
IdGeneratorOptions options = BuildIdGenOptions(1); | |||||
options.Method = method; | |||||
options.WorkerId = 1; | |||||
options.SeqBitLength = 6; | |||||
SetIdGenerator(options); | |||||
pthread_t tid[threadCount]; | |||||
while (1) { | |||||
if (multiThread) { | |||||
for (int i = 0; i < threadCount; i++) { | |||||
if (pthread_create(&tid[i], NULL, (void *) RunMultiThread, NULL) != 0) { | |||||
printf("thread creation failed\n"); | |||||
exit(1); | |||||
} | |||||
} | |||||
} else { | |||||
RunSingle(); | |||||
} | |||||
sleep(1); | |||||
} | |||||
} |