@@ -64,12 +64,17 @@ namespace Yitter.OrgSystem.TestA | |||
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)] | |||
public static extern long NextId(); | |||
[DllImport("yitidgenc.dll", CallingConvention = CallingConvention.StdCall)] | |||
public static extern void SetWorkerId(int workerId); | |||
private static void CallDll() | |||
{ | |||
int i = 0; | |||
long id = 0; | |||
DateTime start = DateTime.Now; | |||
SetWorkerId(1); | |||
while (i < 50000) | |||
{ | |||
id = NextId(); | |||
@@ -1,6 +1,8 @@ | |||
# 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); | |||
} | |||
} |