From 42338403077816ae6a080ed46eb1638557c2e2c8 Mon Sep 17 00:00:00 2001 From: yitter Date: Sat, 27 Mar 2021 22:00:52 +0800 Subject: [PATCH] commitClang --- C#.NET/source/Yitter.IdGenTest/Program.cs | 5 + C/README.md | 6 +- C/source/.gitignore | 258 ++++++++++++++++++++++ C/source/CMakeLists.txt | 27 +++ C/source/YitIdHelper.c | 22 ++ C/source/YitIdHelper.h | 15 ++ C/source/idgen/CMakeLists.txt | 7 + C/source/idgen/IdGenOptions.c | 34 +++ C/source/idgen/IdGenOptions.h | 31 +++ C/source/idgen/IdGenerator.c | 107 +++++++++ C/source/idgen/IdGenerator.h | 30 +++ C/source/idgen/SnowWorkerM1.c | 154 +++++++++++++ C/source/idgen/SnowWorkerM1.h | 53 +++++ C/source/idgen/SnowWorkerM2.c | 30 +++ C/source/idgen/SnowWorkerM2.h | 13 ++ C/source/main.c | 67 ++++++ 16 files changed, 857 insertions(+), 2 deletions(-) create mode 100644 C/source/.gitignore create mode 100644 C/source/CMakeLists.txt create mode 100644 C/source/YitIdHelper.c create mode 100644 C/source/YitIdHelper.h create mode 100644 C/source/idgen/CMakeLists.txt create mode 100644 C/source/idgen/IdGenOptions.c create mode 100644 C/source/idgen/IdGenOptions.h create mode 100644 C/source/idgen/IdGenerator.c create mode 100644 C/source/idgen/IdGenerator.h create mode 100644 C/source/idgen/SnowWorkerM1.c create mode 100644 C/source/idgen/SnowWorkerM1.h create mode 100644 C/source/idgen/SnowWorkerM2.c create mode 100644 C/source/idgen/SnowWorkerM2.h create mode 100644 C/source/main.c diff --git a/C#.NET/source/Yitter.IdGenTest/Program.cs b/C#.NET/source/Yitter.IdGenTest/Program.cs index 8c8cc9c..4c614ae 100644 --- a/C#.NET/source/Yitter.IdGenTest/Program.cs +++ b/C#.NET/source/Yitter.IdGenTest/Program.cs @@ -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(); diff --git a/C/README.md b/C/README.md index 6e542f7..4b7ea56 100644 --- a/C/README.md +++ b/C/README.md @@ -1,6 +1,8 @@ # idgenerator -something is going on. +## 编译说明 -using c +1.默认是 Linux 环境,用 CMake。 + +2.如果是 Windows 环境,要用 Cygwin 或 MinGW。 diff --git a/C/source/.gitignore b/C/source/.gitignore new file mode 100644 index 0000000..a574516 --- /dev/null +++ b/C/source/.gitignore @@ -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 diff --git a/C/source/CMakeLists.txt b/C/source/CMakeLists.txt new file mode 100644 index 0000000..8898c7b --- /dev/null +++ b/C/source/CMakeLists.txt @@ -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) + + diff --git a/C/source/YitIdHelper.c b/C/source/YitIdHelper.c new file mode 100644 index 0000000..d84a72f --- /dev/null +++ b/C/source/YitIdHelper.c @@ -0,0 +1,22 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#include +#include +#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(); +} + diff --git a/C/source/YitIdHelper.h b/C/source/YitIdHelper.h new file mode 100644 index 0000000..9ac2a05 --- /dev/null +++ b/C/source/YitIdHelper.h @@ -0,0 +1,15 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://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(); + diff --git a/C/source/idgen/CMakeLists.txt b/C/source/idgen/CMakeLists.txt new file mode 100644 index 0000000..9b9e8e1 --- /dev/null +++ b/C/source/idgen/CMakeLists.txt @@ -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) + diff --git a/C/source/idgen/IdGenOptions.c b/C/source/idgen/IdGenOptions.c new file mode 100644 index 0000000..440d671 --- /dev/null +++ b/C/source/idgen/IdGenOptions.c @@ -0,0 +1,34 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://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; +} diff --git a/C/source/idgen/IdGenOptions.h b/C/source/idgen/IdGenOptions.h new file mode 100644 index 0000000..a50aeaf --- /dev/null +++ b/C/source/idgen/IdGenOptions.h @@ -0,0 +1,31 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#pragma once + +#include + + +typedef struct IdGenOptions { + /// 闆姳璁$畻鏂规硶,锛1-婕傜Щ绠楁硶|2-浼犵粺绠楁硶锛夛紝榛樿1 + uint8_t Method; + /// 鍩虹鏃堕棿锛坢s鍗曚綅锛夛紝涓嶈兘瓒呰繃褰撳墠绯荤粺鏃堕棿 + 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); + diff --git a/C/source/idgen/IdGenerator.c b/C/source/idgen/IdGenerator.c new file mode 100644 index 0000000..74b76c6 --- /dev/null +++ b/C/source/idgen/IdGenerator.c @@ -0,0 +1,107 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#include +#include +#include +#include +#include +#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锛歐orkerIdBitLength + 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); + } +} + diff --git a/C/source/idgen/IdGenerator.h b/C/source/idgen/IdGenerator.h new file mode 100644 index 0000000..f9841b7 --- /dev/null +++ b/C/source/idgen/IdGenerator.h @@ -0,0 +1,30 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#pragma once + +#include +#include +#include +#include +#include +#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); + diff --git a/C/source/idgen/SnowWorkerM1.c b/C/source/idgen/SnowWorkerM1.c new file mode 100644 index 0000000..f301b66 --- /dev/null +++ b/C/source/idgen/SnowWorkerM1.c @@ -0,0 +1,154 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 浠g爜缈昏瘧锛歛muluowin + * 浠g爜淇锛歽itter + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#include +#include +#include +#include +#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; +} diff --git a/C/source/idgen/SnowWorkerM1.h b/C/source/idgen/SnowWorkerM1.h new file mode 100644 index 0000000..d2d6925 --- /dev/null +++ b/C/source/idgen/SnowWorkerM1.h @@ -0,0 +1,53 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 浠g爜缈昏瘧锛歛muluowin + * 浠g爜淇锛歽itter + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#pragma once + +#include +#include +#include +#include +#include +#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(); + diff --git a/C/source/idgen/SnowWorkerM2.c b/C/source/idgen/SnowWorkerM2.c new file mode 100644 index 0000000..2718aac --- /dev/null +++ b/C/source/idgen/SnowWorkerM2.c @@ -0,0 +1,30 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 浠g爜缈昏瘧锛歛muluowin + * 浠g爜淇锛歽itter + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#include +#include +#include +#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; +} diff --git a/C/source/idgen/SnowWorkerM2.h b/C/source/idgen/SnowWorkerM2.h new file mode 100644 index 0000000..6109601 --- /dev/null +++ b/C/source/idgen/SnowWorkerM2.h @@ -0,0 +1,13 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 浠g爜缈昏瘧锛歛muluowin + * 浠g爜淇锛歽itter + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#pragma once + +#include +#include "SnowWorkerM1.h" + + +extern uint64_t WorkerM2NextId(SnowFlakeWorker *worker); diff --git a/C/source/main.c b/C/source/main.c new file mode 100644 index 0000000..19221e1 --- /dev/null +++ b/C/source/main.c @@ -0,0 +1,67 @@ +/* + * 鐗堟潈灞炰簬锛歽itter(yitter@126.com) + * 浠g爜缈昏瘧锛歛muluowin + * 浠g爜淇锛歽itter + * 寮婧愬湴鍧锛歨ttps://gitee.com/yitter/idgenerator + */ +#include +#include +#include +#include +#include +#include +#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锛宼otal锛%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锛宼otal锛%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); + } +}