| @@ -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); | |||
| } | |||
| } | |||