# Conflicts: # Go/regworkerid/regworkerid/reghelper.go # Go/source/main.gopull/19/MERGE
@@ -7,6 +7,7 @@ | |||
*.userosscache | |||
*.sln.docstates | |||
*.editorconfig | |||
__*.bat | |||
# User-specific files (MonoDevelop/Xamarin Studio) | |||
*.userprefs | |||
@@ -1,7 +1,7 @@ | |||
| |||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||
# Visual Studio Version 16 | |||
VisualStudioVersion = 16.0.31005.135 | |||
# Visual Studio Version 17 | |||
VisualStudioVersion = 17.2.32602.215 | |||
MinimumVisualStudioVersion = 10.0.40219.1 | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yitter.IdGenerator", "Yitter.IdGenerator\Yitter.IdGenerator.csproj", "{FF8DAF11-34E7-4842-ADF2-3722A1A5FBB2}" | |||
EndProject | |||
@@ -1,5 +1,6 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Runtime.InteropServices; | |||
using System.Threading; | |||
@@ -11,7 +12,7 @@ namespace Yitter.OrgSystem.TestA | |||
class Program | |||
{ | |||
// 测试参数(默认配置下,最佳性能是10W/s) | |||
static int genIdCount = 2;//50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength) | |||
static int genIdCount = 50000;//5000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为2000或适当增加SeqBitLength) | |||
static short method = 1; // 1-漂移算法,2-传统算法 | |||
@@ -26,23 +27,24 @@ namespace Yitter.OrgSystem.TestA | |||
static void Main(string[] args) | |||
{ | |||
RunSingle(); | |||
return; | |||
Console.WriteLine("Hello World! C#"); | |||
var options = new IdGeneratorOptions() | |||
{ | |||
Method = method, | |||
Method = 1, | |||
WorkerId = 1, | |||
WorkerIdBitLength = 6, | |||
SeqBitLength = 6, | |||
DataCenterIdBitLength = 10, | |||
DataCenterIdBitLength = 0, | |||
TopOverCostCount = 2000, | |||
//TimestampType = 1, | |||
// MinSeqNumber = 1, | |||
// MaxSeqNumber = 200, | |||
// BaseTime = DateTime.Now.AddYears(-10), | |||
}; | |||
@@ -55,27 +57,118 @@ namespace Yitter.OrgSystem.TestA | |||
Console.WriteLine("====================================="); | |||
Console.WriteLine("这是用方法 " + method + " 生成的 Id:" + newId); | |||
while (true) | |||
var seed1 = 50; | |||
var seed2 = 1000; | |||
var finish = 0; | |||
var next = IdGen.NewLong(); | |||
var hashSet = new HashSet<long>(seed1 * seed2); | |||
ConcurrentBag<long> bags = new ConcurrentBag<long>(); | |||
for (int i = 0; i < seed1; i++) | |||
{ | |||
(new Thread(_ => | |||
{ | |||
for (int j = 0; j < seed2; j++) | |||
{ | |||
var me = IdGen.NewLong(); | |||
hashSet.Add(me); | |||
bags.Add(me); | |||
} | |||
Interlocked.Increment(ref finish); | |||
}) | |||
{ IsBackground = true }).Start(); | |||
} | |||
while (finish < seed1) | |||
{ | |||
RunSingle(); | |||
//CallDll(); | |||
//Go(options); | |||
Thread.Sleep(1000); // 每隔1秒执行一次Go | |||
Console.WriteLine("等待执行结束"); | |||
Thread.Sleep(2000); | |||
} | |||
Console.WriteLine($"hashSet 共计:{hashSet.Count} 实际应该:{seed1 * seed2}"); | |||
Console.WriteLine($"bags 共计:{bags.Count} 实际应该:{seed1 * seed2}"); | |||
var IdArray = bags.ToArray(); | |||
int totalCount = 0; | |||
for (int i = 0; i < seed1 * seed2; i++) | |||
{ | |||
var me = IdArray[i]; | |||
int j = 0; | |||
int count = 0; | |||
while (j < seed1 * seed2) | |||
{ | |||
if (IdArray[j] == me) | |||
{ | |||
count++; | |||
} | |||
j++; | |||
} | |||
if (count > 1) | |||
{ | |||
totalCount++; | |||
Console.WriteLine($"{IdArray[i]},重复:{count}"); | |||
} | |||
} | |||
if (totalCount == 0) | |||
{ | |||
Console.WriteLine($"重复数为 0 "); | |||
} | |||
Console.Read(); | |||
//while (true) | |||
//{ | |||
// //RunSingle(); | |||
// //CallDll(); | |||
// //Go(options); | |||
// Thread.Sleep(1000); // 每隔1秒执行一次Go | |||
//} | |||
} | |||
private static void RunSingle() | |||
{ | |||
DateTime start = DateTime.Now; | |||
for (int i = 0; i < genIdCount; i++) | |||
var options = new IdGeneratorOptions() | |||
{ | |||
var id = IdGen.NewLong(); | |||
} | |||
Method = 1, | |||
WorkerId = 1, | |||
//WorkerIdBitLength = 6, | |||
SeqBitLength = 6, | |||
//TopOverCostCount = 2000, | |||
//DataCenterIdBitLength = 0, | |||
//TimestampType = 1, | |||
// MinSeqNumber = 1, | |||
// MaxSeqNumber = 200, | |||
// BaseTime = DateTime.Now.AddYears(-10), | |||
}; | |||
DateTime end = DateTime.Now; | |||
Console.WriteLine($"++++++++++++++++++++++++++++++++++++++++, total: {(end - start).TotalMilliseconds} ms"); | |||
Interlocked.Increment(ref Program.Count); | |||
//IdGen = new DefaultIdGenerator(options); | |||
YitIdHelper.SetIdGenerator(options); | |||
while (true) | |||
{ | |||
DateTime start = DateTime.Now; | |||
for (int i = 0; i < genIdCount; i++) | |||
{ | |||
//var id = IdGen.NewLong(); | |||
var id = YitIdHelper.NextId(); | |||
} | |||
DateTime end = DateTime.Now; | |||
Console.WriteLine($"++++++++++++++++++++++++++++++++++++++++, total: {(end - start).TotalMilliseconds} ms"); | |||
Thread.Sleep(1000); | |||
} | |||
//Interlocked.Increment(ref Program.Count); | |||
} | |||
private static void Go(IdGeneratorOptions options) | |||
@@ -2,7 +2,7 @@ | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>net5.0</TargetFramework> | |||
<TargetFramework>net6.0</TargetFramework> | |||
</PropertyGroup> | |||
<PropertyGroup> | |||
@@ -63,7 +63,6 @@ namespace Yitter.IdGenerator | |||
/// </summary> | |||
public virtual int TopOverCostCount { get; set; } = 2000; | |||
/// <summary> | |||
/// 数据中心ID(默认0) | |||
/// </summary> | |||
@@ -118,10 +118,10 @@ namespace Yitter.IdGenerator | |||
// 7.Others | |||
TopOverCostCount = options.TopOverCostCount; | |||
if (TopOverCostCount == 0) | |||
{ | |||
TopOverCostCount = 2000; | |||
} | |||
//if (TopOverCostCount == 0) | |||
//{ | |||
// TopOverCostCount = 2000; | |||
//} | |||
_TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength); | |||
_CurrentSeqNumber = options.MinSeqNumber; | |||
@@ -351,6 +351,7 @@ namespace Yitter.IdGenerator | |||
while (tempTimeTicker <= _LastTimeTick) | |||
{ | |||
Thread.Sleep(1); | |||
tempTimeTicker = GetCurrentTimeTick(); | |||
} | |||
@@ -92,6 +92,12 @@ namespace Yitter.IdGenerator | |||
throw new ApplicationException("MinSeqNumber error. (range:[5, " + maxSeqNumber + "]"); | |||
} | |||
// 7.TopOverCostCount | |||
if (options.TopOverCostCount < 0 || options.TopOverCostCount > 10000) | |||
{ | |||
throw new ApplicationException("TopOverCostCount error. (range:[0, 10000]"); | |||
} | |||
switch (options.Method) | |||
{ | |||
case 2: | |||
@@ -34,17 +34,24 @@ namespace Yitter.IdGenerator | |||
/// <summary> | |||
/// 生成新的Id | |||
/// 调用本方法前,请确保调用了 SetIdGenerator 方法做初始化。 | |||
/// 否则将会初始化一个WorkerId为1的对象。 | |||
/// </summary> | |||
/// <returns></returns> | |||
public static long NextId() | |||
{ | |||
if (_IdGenInstance == null) | |||
{ | |||
_IdGenInstance = new DefaultIdGenerator( | |||
new IdGeneratorOptions() { WorkerId = 0 } | |||
); | |||
} | |||
//if (_IdGenInstance == null) | |||
//{ | |||
// lock (_IdGenInstance) | |||
// { | |||
// if (_IdGenInstance == null) | |||
// { | |||
// _IdGenInstance = new DefaultIdGenerator( | |||
// new IdGeneratorOptions() { WorkerId = 0 } | |||
// ); | |||
// } | |||
// } | |||
//} | |||
if (_IdGenInstance == null) throw new ApplicationException("Please initialize Yitter.IdGeneratorOptions first."); | |||
return _IdGenInstance.NewLong(); | |||
} | |||
@@ -18,8 +18,10 @@ | |||
<Copyright>Yitter</Copyright> | |||
<PackageProjectUrl>https://github.com/yitter/idgenerator</PackageProjectUrl> | |||
<PackageLicenseExpression>MIT</PackageLicenseExpression> | |||
<Version>1.0.12</Version> | |||
<Version>1.0.14</Version> | |||
<PackageReleaseNotes></PackageReleaseNotes> | |||
<AssemblyVersion>1.0.0.*</AssemblyVersion> | |||
<FileVersion>1.0.0.*</FileVersion> | |||
</PropertyGroup> | |||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> | |||
@@ -1,7 +1,7 @@ | |||
## Ignore Visual Studio temporary files, build results, and | |||
## files generated by popular Visual Studio add-ons. | |||
build/* | |||
build | |||
# User-specific files | |||
*.suo | |||
@@ -29,6 +29,7 @@ bld/ | |||
**/.vs/ | |||
# Uncomment if you have tasks that create the project's static files in wwwroot | |||
#wwwroot/ | |||
.vscode | |||
# MSTest test Results | |||
[Tt]est[Rr]esult*/ | |||
@@ -254,7 +255,8 @@ paket-files/ | |||
.idea/ | |||
*.sln.iml | |||
target/ | |||
cmake-build*/ | |||
cmake-build-* | |||
source.code-* | |||
# macOS | |||
.DS_Store |
@@ -8,18 +8,17 @@ set(CMAKE_C_STANDARD 11) | |||
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(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(YitIdGen YitIdHelper pthread) | |||
@@ -9,107 +9,147 @@ | |||
#include <unistd.h> | |||
#include "IdGenerator.h" | |||
static inline uint64_t WorkerM1Id() { | |||
static inline uint64_t WorkerM1Id() | |||
{ | |||
return WorkerM1NextId(_idGenerator->Worker); | |||
} | |||
static inline uint64_t WorkerM2Id() { | |||
static inline uint64_t WorkerM2Id() | |||
{ | |||
return WorkerM2NextId(_idGenerator->Worker); | |||
} | |||
extern IdGenerator *GetIdGenInstance() { | |||
extern IdGenerator *GetIdGenInstance() | |||
{ | |||
if (_idGenerator != NULL) | |||
return _idGenerator; | |||
else { | |||
_idGenerator = (IdGenerator *) malloc(sizeof(IdGenerator)); | |||
else | |||
{ | |||
_idGenerator = (IdGenerator *)malloc(sizeof(IdGenerator)); | |||
_idGenerator->Worker = NewSnowFlakeWorker(); | |||
return _idGenerator; | |||
} | |||
} | |||
extern void SetOptions(IdGeneratorOptions options) { | |||
if (GetIdGenInstance() == NULL) { | |||
extern void SetOptions(IdGeneratorOptions options) | |||
{ | |||
if (GetIdGenInstance() == NULL) | |||
{ | |||
exit(1); | |||
} | |||
// 1.BaseTime | |||
if (options.BaseTime == 0) { | |||
if (options.BaseTime == 0) | |||
{ | |||
_idGenerator->Worker->BaseTime = 1582136402000; | |||
} else if (options.BaseTime < 631123200000 || options.BaseTime > GetCurrentTime()) { | |||
} | |||
else if (options.BaseTime < 631123200000 || options.BaseTime > GetCurrentTime()) | |||
{ | |||
perror("BaseTime error."); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
_idGenerator->Worker->BaseTime = options.BaseTime; | |||
} | |||
// 2.WorkerIdBitLength | |||
if (options.WorkerIdBitLength <= 0) { | |||
if (options.WorkerIdBitLength <= 0) | |||
{ | |||
perror("WorkerIdBitLength error.(range:[1, 21])"); | |||
exit(1); | |||
} | |||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) { | |||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) | |||
{ | |||
perror("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
// _idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength; | |||
_idGenerator->Worker->WorkerIdBitLength = options.WorkerIdBitLength <= 0 ? 6 : options.WorkerIdBitLength; | |||
} | |||
// 3.WorkerId | |||
uint32_t maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1; | |||
if (maxWorkerIdNumber == 0) { | |||
if (maxWorkerIdNumber == 0) | |||
{ | |||
maxWorkerIdNumber = 63; | |||
} | |||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) { | |||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) | |||
{ | |||
perror("WorkerId error. (range:[0, {2^options.WorkerIdBitLength-1]}"); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
_idGenerator->Worker->WorkerId = options.WorkerId; | |||
} | |||
// 4.SeqBitLength | |||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) { | |||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) | |||
{ | |||
perror("SeqBitLength error. (range:[2, 21])"); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
// _idGenerator->Worker->SeqBitLength = options.SeqBitLength; | |||
_idGenerator->Worker->SeqBitLength = options.SeqBitLength <= 0 ? 6 : options.SeqBitLength; | |||
} | |||
// 5.MaxSeqNumber | |||
uint32_t maxSeqNumber = (1 << options.SeqBitLength) - 1; | |||
if (maxSeqNumber == 0) { | |||
if (maxSeqNumber == 0) | |||
{ | |||
maxSeqNumber = 63; | |||
} | |||
if (options.MaxSeqNumber > maxSeqNumber) { | |||
if (options.MaxSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MaxSeqNumber error. (range:[1, {2^options.SeqBitLength-1}]"); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
_idGenerator->Worker->MaxSeqNumber = options.MaxSeqNumber <= 0 ? maxSeqNumber : options.MaxSeqNumber; | |||
} | |||
// 6.MinSeqNumber | |||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber) { | |||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MinSeqNumber error. (range:[5, {options.MinSeqNumber}]"); | |||
exit(1); | |||
} else { | |||
} | |||
else | |||
{ | |||
_idGenerator->Worker->MinSeqNumber = options.MinSeqNumber <= 0 ? 5 : options.MinSeqNumber; | |||
} | |||
// 7.Others | |||
_idGenerator->Worker->TopOverCostCount = options.TopOverCostCount <= 0 ? 2000 : options.TopOverCostCount; | |||
// 7.TopOverCostCount | |||
if (options.TopOverCostCount < 0 || options.TopOverCostCount > 10000) | |||
{ | |||
perror("TopOverCostCount error. (range:[0, 10000]"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
//_idGenerator->Worker->TopOverCostCount = options.TopOverCostCount <= 0 ? 2000 : options.TopOverCostCount; | |||
_idGenerator->Worker->TopOverCostCount = options.TopOverCostCount; | |||
} | |||
// 8.Others | |||
_idGenerator->Worker->_TimestampShift = | |||
_idGenerator->Worker->WorkerIdBitLength + _idGenerator->Worker->SeqBitLength; | |||
_idGenerator->Worker->WorkerIdBitLength + _idGenerator->Worker->SeqBitLength; | |||
_idGenerator->Worker->_CurrentSeqNumber = _idGenerator->Worker->MinSeqNumber; | |||
_idGenerator->Worker->Method = options.Method; | |||
if (options.Method == 2) { | |||
if (options.Method == 2) | |||
{ | |||
_idGenerator->NextId = WorkerM2Id; | |||
} else { | |||
} | |||
else | |||
{ | |||
_idGenerator->NextId = WorkerM1Id; | |||
sleep(1); | |||
usleep(500 * 1000); // 暂停500ms | |||
} | |||
} | |||
@@ -162,6 +162,7 @@ extern int64_t GetCurrentMicroTime() { | |||
extern int64_t GetNextTimeTick(SnowFlakeWorker *worker) { | |||
uint64_t tempTimeTicker = GetCurrentTimeTick(worker); | |||
while (tempTimeTicker <= worker->_LastTimeTick) { | |||
usleep(1000); // 暂停1ms | |||
tempTimeTicker = GetCurrentTimeTick(worker); | |||
} | |||
return tempTimeTicker; | |||
@@ -13,51 +13,62 @@ | |||
#include "idgen/IdGenerator.h" | |||
#include "YitIdHelper.h" | |||
const int GenIdCount = 50000; | |||
const int GenIdCount = 500000; | |||
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++) { | |||
void RunMultiThread() | |||
{ | |||
// int64_t start = GetCurrentMicroTime(); | |||
for (int i = 0; i < GenIdCount / threadCount; i++) | |||
{ | |||
int64_t id = NextId(); | |||
printf("ID: %D\n", id); | |||
} | |||
int64_t end = GetCurrentMicroTime(); | |||
//printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start)); | |||
// printf("%s,total:%d μs\n", method == 1 ? "1" : "2", (end - start)); | |||
} | |||
void RunSingle() { | |||
void RunSingle() | |||
{ | |||
int64_t start = GetCurrentMicroTime(); | |||
for (int i = 0; i < GenIdCount; i++) { | |||
for (int i = 0; i < GenIdCount; i++) | |||
{ | |||
int64_t id = NextId(); | |||
// printf("ID: %ld\n", id); | |||
// printf("ID: %ld\n", id); | |||
} | |||
int64_t end = GetCurrentMicroTime(); | |||
printf("%s, total: %d us\n", method == 1 ? "1" : "2", (end - start)); | |||
} | |||
int main() { | |||
int main() | |||
{ | |||
IdGeneratorOptions options = BuildIdGenOptions(1); | |||
options.Method = method; | |||
options.WorkerId = 1; | |||
options.SeqBitLength = 6; | |||
options.SeqBitLength = 10; | |||
// options.TopOverCostCount = 2000; | |||
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) { | |||
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 { | |||
} | |||
else | |||
{ | |||
RunSingle(); | |||
} | |||
@@ -31,7 +31,7 @@ var newId = idgen.NextId() | |||
## 关于Go环境 | |||
1.SDK,go1.14 | |||
1.SDK,go1.16 | |||
2.启用 Go-Modules | |||
``` | |||
@@ -0,0 +1,262 @@ | |||
## 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 | |||
.vscode | |||
__commit.bat | |||
__download.bat | |||
target | |||
# 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/ | |||
dlldata.c | |||
# 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 | |||
# macOS | |||
.DS_Store |
@@ -0,0 +1,10 @@ | |||
module github.com/yitter/idgenerator-go | |||
go 1.17 | |||
require github.com/go-redis/redis/v8 v8.11.5 | |||
require ( | |||
github.com/cespare/xxhash/v2 v2.1.2 // indirect | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect | |||
) |
@@ -0,0 +1,106 @@ | |||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= | |||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | |||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= | |||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | |||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | |||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | |||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= | |||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= | |||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | |||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | |||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | |||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | |||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | |||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= | |||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | |||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | |||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= | |||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= | |||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= | |||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= | |||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= | |||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= | |||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= | |||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= | |||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= | |||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= | |||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= | |||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= | |||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | |||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | |||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= | |||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= | |||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= | |||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | |||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | |||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | |||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | |||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | |||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | |||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | |||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | |||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
@@ -0,0 +1,69 @@ | |||
package main | |||
import ( | |||
"C" | |||
"fmt" | |||
"time" | |||
"github.com/yitter/idgenerator-go/regworkerid" | |||
) | |||
func main() { | |||
ip := "localhost" | |||
password := "" | |||
ipChar := C.CString(ip) | |||
passChar := C.CString(password) | |||
workerIdList := RegisterMany(ipChar, 6379, passChar, 4, 3, 0) | |||
for _, value := range workerIdList { | |||
fmt.Println("注册的WorkerId:", value) | |||
} | |||
id := RegisterOne(ipChar, 6379, passChar, 4, 0) | |||
fmt.Println("注册的WorkerId:", id) | |||
// var workerId = regworkerid.RegisterOne(ip, 6379, "", 4) | |||
// fmt.Println("注册的WorkerId:", workerId) | |||
fmt.Println("end") | |||
time.Sleep(time.Duration(300) * time.Second) | |||
} | |||
//export RegisterOne | |||
// 注册一个 WorkerId | |||
func RegisterOne(ip *C.char, port int32, password *C.char, maxWorkerId int32, database int) int32 { | |||
return regworkerid.RegisterOne(C.GoString(ip), port, C.GoString(password), maxWorkerId, database) | |||
} | |||
//export UnRegister | |||
// 注销本机已注册的 WorkerId | |||
func UnRegister() { | |||
regworkerid.UnRegister() | |||
} | |||
// export Validate | |||
// 检查本地WorkerId是否有效(0-有效,其它-无效) | |||
func Validate(workerId int32) int32 { | |||
return regworkerid.Validate(workerId) | |||
} | |||
// RegisterMany | |||
// 注册多个 WorkerId,会先注销所有本机已注册的记录 | |||
func RegisterMany(ip *C.char, port int32, password *C.char, maxWorkerId, totalCount int32, database int) []int32 { | |||
// return (*C.int)(unsafe.Pointer(&values)) | |||
//return regworkerid.RegisterMany(ip, port, password, maxWorkerId, totalCount, database) | |||
return regworkerid.RegisterMany(C.GoString(ip), port, C.GoString(password), maxWorkerId, totalCount, database) | |||
} | |||
// To Build a dll/so: | |||
// windows: | |||
// go build -o ./target/yitidgengo.dll -buildmode=c-shared main.go | |||
// // go build -o ./target/yitidgengo.dll -buildmode=c-shared main.go reg.go | |||
// linux init: go install -buildmode=shared -linkshared std | |||
// go build -o ./target/yitidgengo.so -buildmode=c-shared main.go | |||
// go build -o ./target/yitidgengo.so -buildmode=c-shared main.go reg.go | |||
// https://books.studygolang.com/advanced-go-programming-book/ch2-cgo/ch2-09-static-shared-lib.html |
@@ -0,0 +1,5 @@ | |||
package main | |||
import ( | |||
"C" | |||
) |
@@ -0,0 +1,262 @@ | |||
## 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 | |||
.vscode | |||
__commit.bat | |||
__download.bat | |||
target | |||
# 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/ | |||
dlldata.c | |||
# 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 | |||
# macOS | |||
.DS_Store |
@@ -1,5 +1,8 @@ | |||
module yitidgen | |||
go 1.16 | |||
require github.com/go-redis/redis/v8 v8.8.0 // indirect | |||
module github.com/yitter/idgenerator-go | |||
go 1.17 | |||
require ( | |||
github.com/cespare/xxhash/v2 v2.1.2 // indirect | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect | |||
) |
@@ -1,15 +1,18 @@ | |||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= | |||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | |||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= | |||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | |||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= | |||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= | |||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | |||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | |||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | |||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | |||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | |||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= | |||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | |||
github.com/go-redis/redis/v8 v8.8.0 h1:fDZP58UN/1RD3DjtTXP/fFZ04TFohSYhjZDkcDe2dnw= | |||
github.com/go-redis/redis/v8 v8.8.0/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= | |||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= | |||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= | |||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | |||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | |||
@@ -17,38 +20,33 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU | |||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | |||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | |||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= | |||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= | |||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= | |||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | |||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | |||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= | |||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= | |||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= | |||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= | |||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= | |||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= | |||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | |||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= | |||
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= | |||
github.com/onsi/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org= | |||
github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o= | |||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= | |||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= | |||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= | |||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= | |||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= | |||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= | |||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= | |||
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug= | |||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= | |||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= | |||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= | |||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | |||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng= | |||
go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg= | |||
go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg= | |||
go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc= | |||
go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA= | |||
go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc= | |||
go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
@@ -58,8 +56,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn | |||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | |||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= | |||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | |||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= | |||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= | |||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
@@ -69,35 +67,40 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w | |||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw= | |||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= | |||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | |||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= | |||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | |||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | |||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | |||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | |||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | |||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= | |||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | |||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | |||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | |||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
@@ -4,6 +4,7 @@ | |||
* 代码修订:yitter | |||
* 开源地址:https://github.com/yitter/idgenerator | |||
*/ | |||
package idgen | |||
import ( | |||
@@ -64,6 +65,11 @@ func NewDefaultIdGenerator(options *IdGeneratorOptions) *DefaultIdGenerator { | |||
panic("MinSeqNumber error. (range:[5, " + strconv.FormatUint(uint64(maxSeqNumber), 10) + "]") | |||
} | |||
// 7.TopOverCostCount | |||
if options.TopOverCostCount < 0 || options.TopOverCostCount > 10000 { | |||
panic("TopOverCostCount error. (range:[0, 10000]") | |||
} | |||
var snowWorker ISnowWorker | |||
switch options.Method { | |||
case 1: | |||
@@ -87,3 +93,7 @@ func NewDefaultIdGenerator(options *IdGeneratorOptions) *DefaultIdGenerator { | |||
func (dig DefaultIdGenerator) NewLong() int64 { | |||
return dig.SnowWorker.NextId() | |||
} | |||
func (dig DefaultIdGenerator) ExtractTime(id int64) time.Time { | |||
return time.UnixMilli(id>>(dig.Options.WorkerIdBitLength+dig.Options.SeqBitLength) + dig.Options.BaseTime) | |||
} |
@@ -4,6 +4,7 @@ | |||
* 代码修订:yitter | |||
* 开源地址:https://github.com/yitter/idgenerator | |||
*/ | |||
package idgen | |||
import ( | |||
@@ -13,13 +14,13 @@ import ( | |||
// SnowWorkerM1 . | |||
type SnowWorkerM1 struct { | |||
BaseTime int64 //基础时间 | |||
WorkerId uint16 //机器码 | |||
WorkerIdBitLength byte //机器码位长 | |||
SeqBitLength byte //自增序列数位长 | |||
MaxSeqNumber uint32 //最大序列数(含) | |||
MinSeqNumber uint32 //最小序列数(含) | |||
TopOverCostCount uint32 //最大漂移次数 | |||
BaseTime int64 // 基础时间 | |||
WorkerId uint16 // 机器码 | |||
WorkerIdBitLength byte // 机器码位长 | |||
SeqBitLength byte // 自增序列数位长 | |||
MaxSeqNumber uint32 // 最大序列数(含) | |||
MinSeqNumber uint32 // 最小序列数(含) | |||
TopOverCostCount uint32 // 最大漂移次数 | |||
_TimestampShift byte | |||
_CurrentSeqNumber uint32 | |||
@@ -75,12 +76,13 @@ func NewSnowWorkerM1(options *IdGeneratorOptions) ISnowWorker { | |||
// 6.MinSeqNumber | |||
var minSeqNumber = options.MinSeqNumber | |||
// 7.Others | |||
// 7.TopOverCostCount | |||
var topOverCostCount = options.TopOverCostCount | |||
if topOverCostCount == 0 { | |||
topOverCostCount = 2000 | |||
} | |||
// if topOverCostCount == 0 { | |||
// topOverCostCount = 2000 | |||
// } | |||
// 8.Others | |||
timestampShift := (byte)(workerIdBitLength + seqBitLength) | |||
currentSeqNumber := minSeqNumber | |||
@@ -232,6 +234,7 @@ func (m1 *SnowWorkerM1) GetCurrentTimeTick() int64 { | |||
func (m1 *SnowWorkerM1) GetNextTimeTick() int64 { | |||
tempTimeTicker := m1.GetCurrentTimeTick() | |||
for tempTimeTicker <= m1._LastTimeTick { | |||
time.Sleep(time.Duration(1) * time.Millisecond) | |||
tempTimeTicker = m1.GetCurrentTimeTick() | |||
} | |||
return tempTimeTicker | |||
@@ -1,7 +1,15 @@ | |||
/* | |||
* 版权属于:yitter(yitter@126.com) | |||
* 代码编辑:guoyahao | |||
* 代码修订:yitter | |||
* 开源地址:https://github.com/yitter/idgenerator | |||
*/ | |||
package idgen | |||
import ( | |||
"sync" | |||
"time" | |||
) | |||
var singletonMutex sync.Mutex | |||
@@ -16,14 +24,20 @@ func SetIdGenerator(options *IdGeneratorOptions) { | |||
// NextId . | |||
func NextId() int64 { | |||
//if idGenerator == nil { | |||
// singletonMutex.Lock() | |||
// defer singletonMutex.Unlock() | |||
// if idGenerator == nil { | |||
// options := NewIdGeneratorOptions(1) | |||
// idGenerator = NewDefaultIdGenerator(options) | |||
// } | |||
//} | |||
if idGenerator == nil { | |||
singletonMutex.Lock() | |||
defer singletonMutex.Unlock() | |||
if idGenerator == nil { | |||
options := NewIdGeneratorOptions(1) | |||
idGenerator = NewDefaultIdGenerator(options) | |||
} | |||
panic("Please initialize Yitter.IdGeneratorOptions first.") | |||
} | |||
return idGenerator.NewLong() | |||
} | |||
func ExtractTime(id int64) time.Time { | |||
return idGenerator.ExtractTime(id) | |||
} |
@@ -1,136 +1,52 @@ | |||
package main | |||
import ( | |||
"C" | |||
"fmt" | |||
"time" | |||
"yitidgen/idgen" | |||
"yitidgen/regworkerid" | |||
"github.com/yitter/idgenerator-go/idgen" | |||
) | |||
//export SetOptions | |||
func SetOptions(workerId uint16) { | |||
var options = idgen.NewIdGeneratorOptions(workerId) | |||
idgen.SetIdGenerator(options) | |||
} | |||
//export NextId | |||
func NextId() int64 { | |||
return idgen.NextId() | |||
} | |||
// RegisterOne 注册一个 WorkerId,会先注销所有本机已注册的记录 | |||
// address: Redis连接地址,单机模式示例:127.0.0.1:6379,哨兵/集群模式示例:127.0.0.1:26380,127.0.0.1:26381,127.0.0.1:26382 | |||
// password: Redis连接密码 | |||
// db: Redis指定存储库,示例:1 | |||
// sentinelMasterName: Redis 哨兵模式下的服务名称,示例:mymaster | |||
// maxWorkerId: WorkerId 最大值,示例:63 | |||
//export RegisterOne | |||
func RegisterOne(address *C.char, password *C.char, db int, sentinelMasterName *C.char, maxWorkerId int32) int32 { | |||
return regworkerid.RegisterOne(regworkerid.RegisterConf{ | |||
Address: C.GoString(address), | |||
Password: C.GoString(password), | |||
DB: db, | |||
MasterName: C.GoString(sentinelMasterName), | |||
MaxWorkerId: maxWorkerId, | |||
}) | |||
} | |||
// RegisterMany 注册多个 WorkerId,会先注销所有本机已注册的记录 | |||
// address: Redis连接地址,单机模式示例:127.0.0.1:6379,哨兵/集群模式示例:127.0.0.1:26380,127.0.0.1:26381,127.0.0.1:26382 | |||
// password: Redis连接密码 | |||
// db: Redis指定存储库,示例:1 | |||
// sentinelMasterName: Redis 哨兵模式下的服务名称,示例:mymaster | |||
// maxWorkerId: WorkerId 最大值,示例:63 | |||
// totalCount: 获取N个WorkerId,示例:5 | |||
//export RegisterMany | |||
func RegisterMany(address *C.char, password *C.char, db int, sentinelMasterName *C.char, maxWorkerId int32, totalCount int32) []int32 { | |||
return regworkerid.RegisterMany(regworkerid.RegisterConf{ | |||
Address: C.GoString(address), | |||
Password: C.GoString(password), | |||
DB: db, | |||
MasterName: C.GoString(sentinelMasterName), | |||
MaxWorkerId: maxWorkerId, | |||
TotalCount: totalCount, | |||
}) | |||
} | |||
// UnRegister 注销本机已注册的 WorkerId | |||
//export UnRegister | |||
func UnRegister() { | |||
regworkerid.UnRegister() | |||
} | |||
// Validate 检查本地WorkerId是否有效(0-有效,其它-无效) | |||
//export Validate | |||
func Validate(workerId int32) int32 { | |||
return regworkerid.Validate(workerId) | |||
} | |||
func main() { | |||
const testGenId = true // 测试设置 | |||
if testGenId { | |||
// 自定义参数 | |||
var options = idgen.NewIdGeneratorOptions(1) | |||
options.WorkerIdBitLength = 6 | |||
options.SeqBitLength = 6 | |||
options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6 | |||
idgen.SetIdGenerator(options) | |||
// 自定义参数 | |||
var options = idgen.NewIdGeneratorOptions(1) | |||
options.WorkerIdBitLength = 6 | |||
options.SeqBitLength = 10 | |||
options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6 | |||
idgen.SetIdGenerator(options) | |||
var genCount = 50000 | |||
var genCount = 500000 | |||
for j := 0; j < 100000; j++ { | |||
for { | |||
var begin = time.Now().UnixNano() / 1e3 | |||
var begin = time.Now().UnixNano() / 1e6 | |||
for i := 0; i < genCount; i++ { | |||
// 生成ID | |||
id := idgen.NextId() | |||
fmt.Println(id) | |||
idgen.NextId() | |||
// fmt.Println(id) | |||
} | |||
var end = time.Now().UnixNano() / 1e3 | |||
var end = time.Now().UnixNano() / 1e6 | |||
fmt.Println(end - begin) | |||
fmt.Println("耗时:", (end - begin), "ms") | |||
time.Sleep(time.Duration(1000) * time.Millisecond) | |||
} | |||
} else { | |||
//// Redis单机模式下,获取多个WorkerId | |||
//workerIdList := regworkerid.RegisterMany(regworkerid.RegisterConf{ | |||
// Address: "127.0.0.1:6379", | |||
// Password: "", | |||
// DB: 0, | |||
// MaxWorkerId: 4, | |||
// TotalCount: 3, | |||
//}) | |||
//for _, value := range workerIdList { | |||
// fmt.Println("RegisterMany--注册的WorkerId:", value) | |||
//} | |||
// Redis单机模式下,获取一个WorkerId | |||
var workerId = regworkerid.RegisterOne(regworkerid.RegisterConf{ | |||
Address: "127.0.0.1:6379", | |||
Password: "", | |||
DB: 0, | |||
MaxWorkerId: 4, | |||
}) | |||
fmt.Println("RegisterOne--注册的WorkerId:", workerId) | |||
//// Redis哨兵模式下,获取一个WorkerId | |||
//var workerId = regworkerid.RegisterOne(regworkerid.RegisterConf{ | |||
// //Address: "127.0.0.1:26380,127.0.0.1:26381,127.0.0.1:26382", | |||
// Password: "", | |||
// DB: 0, | |||
// MasterName: "mymaster", // 哨兵模式下的服务名称 | |||
// MaxWorkerId: 4, | |||
//}) | |||
//fmt.Println("RegisterOne--注册的WorkerId:", workerId) | |||
fmt.Println("end") | |||
time.Sleep(time.Duration(300) * time.Second) | |||
} | |||
} | |||
// To Build a dll/so: | |||
// windows: | |||
// go build -o ./target/yitidgengo.dll -buildmode=c-shared main.go | |||
// linux init: go install -buildmode=shared -linkshared std | |||
// go build -o ./target/yitidgengo.so -buildmode=c-shared main.go | |||
// https://books.studygolang.com/advanced-go-programming-book/ch2-cgo/ch2-09-static-shared-lib.html |
@@ -19,7 +19,9 @@ | |||
*.zip | |||
*.tar.gz | |||
*.rar | |||
target/ | |||
target | |||
.vscode | |||
*.code-workspace | |||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | |||
hs_err_pid* |
@@ -41,9 +41,9 @@ | |||
<properties> | |||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |||
<maven.compiler.source>1.8</maven.compiler.source> | |||
<maven.compiler.target>1.8</maven.compiler.target> | |||
<java.version>1.8</java.version> | |||
<maven.compiler.source>11</maven.compiler.source> | |||
<maven.compiler.target>11</maven.compiler.target> | |||
<java.version>11</java.version> | |||
</properties> | |||
<dependencies> | |||
<dependency> | |||
@@ -66,7 +66,8 @@ public class SnowWorkerM1 implements ISnowWorker { | |||
SeqBitLength = options.SeqBitLength == 0 ? 6 : options.SeqBitLength; | |||
MaxSeqNumber = options.MaxSeqNumber <= 0 ? (1 << SeqBitLength) - 1 : options.MaxSeqNumber; | |||
MinSeqNumber = options.MinSeqNumber; | |||
TopOverCostCount = options.TopOverCostCount == 0 ? 2000 : options.TopOverCostCount; | |||
// TopOverCostCount = options.TopOverCostCount == 0 ? 2000 : options.TopOverCostCount; | |||
TopOverCostCount = options.TopOverCostCount; | |||
_TimestampShift = (byte) (WorkerIdBitLength + SeqBitLength); | |||
_CurrentSeqNumber = MinSeqNumber; | |||
} | |||
@@ -150,11 +151,11 @@ public class SnowWorkerM1 implements ISnowWorker { | |||
BeginTurnBackAction(_TurnBackTimeTick); | |||
} | |||
// try { | |||
// Thread.sleep(1); | |||
// } catch (InterruptedException e) { | |||
// e.printStackTrace(); | |||
// } | |||
// try { | |||
// Thread.sleep(1); | |||
// } catch (InterruptedException e) { | |||
// e.printStackTrace(); | |||
// } | |||
return CalcTurnBackId(_TurnBackTimeTick); | |||
} | |||
@@ -214,6 +215,11 @@ public class SnowWorkerM1 implements ISnowWorker { | |||
long tempTimeTicker = GetCurrentTimeTick(); | |||
while (tempTimeTicker <= _LastTimeTick) { | |||
try { | |||
Thread.sleep(1); | |||
} catch (InterruptedException e) { | |||
e.printStackTrace(); | |||
} | |||
tempTimeTicker = GetCurrentTimeTick(); | |||
} | |||
@@ -227,4 +233,3 @@ public class SnowWorkerM1 implements ISnowWorker { | |||
} | |||
} | |||
} | |||
@@ -11,7 +11,6 @@ import com.github.yitter.contract.IdGeneratorOptions; | |||
import com.github.yitter.core.SnowWorkerM1; | |||
import com.github.yitter.core.SnowWorkerM2; | |||
public class DefaultIdGenerator implements IIdGenerator { | |||
private static ISnowWorker _SnowWorker = null; | |||
@@ -40,7 +39,8 @@ public class DefaultIdGenerator implements IIdGenerator { | |||
maxWorkerIdNumber = 63; | |||
} | |||
if (options.WorkerId < 0 || options.WorkerId > maxWorkerIdNumber) { | |||
throw new IdGeneratorException("WorkerId error. (range:[0, " + (maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63) + "]"); | |||
throw new IdGeneratorException( | |||
"WorkerId error. (range:[0, " + (maxWorkerIdNumber > 0 ? maxWorkerIdNumber : 63) + "]"); | |||
} | |||
// 4.SeqBitLength | |||
@@ -62,6 +62,11 @@ public class DefaultIdGenerator implements IIdGenerator { | |||
throw new IdGeneratorException("MinSeqNumber error. (range:[5, " + maxSeqNumber + "]"); | |||
} | |||
// 7.TopOverCostCount | |||
if (options.TopOverCostCount < 0 || options.TopOverCostCount > 10000) { | |||
throw new IdGeneratorException("TopOverCostCount error. (range:[0, 10000]"); | |||
} | |||
switch (options.Method) { | |||
case 2: | |||
_SnowWorker = new SnowWorkerM2(options); | |||
@@ -19,7 +19,6 @@ public class YitIdHelper { | |||
return idGenInstance; | |||
} | |||
/** | |||
* 设置参数,建议程序初始化时执行一次 | |||
*/ | |||
@@ -34,9 +33,12 @@ public class YitIdHelper { | |||
* @return | |||
*/ | |||
public static long nextId() throws IdGeneratorException { | |||
if (idGenInstance == null) { | |||
idGenInstance = new DefaultIdGenerator(new IdGeneratorOptions((short) 1)); | |||
} | |||
// if (idGenInstance == null) { | |||
// idGenInstance = new DefaultIdGenerator(new IdGeneratorOptions((short) 1)); | |||
// } | |||
if (idGenInstance == null) | |||
throw new IdGeneratorException("Please initialize Yitter.IdGeneratorOptions first."); | |||
return idGenInstance.newLong(); | |||
} | |||
@@ -26,7 +26,7 @@ public class GenTest { | |||
long end = System.currentTimeMillis(); | |||
long time = end - start; | |||
System.out.println(id); | |||
// System.out.println(id); | |||
System.out.println("++++++++++++++++++++++++++++++++++++++++WorkerId: " | |||
+ WorkerId + ", total: " + time + " ms"); | |||
@@ -12,7 +12,7 @@ public class StartUp { | |||
* [不同CPU可能结果有差异,但相对大小不变] | |||
* 默认配置下,最佳性能是5W/s-8W/s | |||
*/ | |||
final static int genIdCount = 50000; | |||
final static int genIdCount = 500000; | |||
//1-漂移算法,2-传统算法 | |||
final static short method = 1; | |||
@@ -20,11 +20,12 @@ public class StartUp { | |||
public static void main(String[] args) { | |||
IdGeneratorOptions options = new IdGeneratorOptions(); | |||
// options.WorkerIdBitLength = 6; | |||
// options.SeqBitLength = 6; | |||
// options.WorkerIdBitLength = 6; // 默认6 | |||
options.SeqBitLength = 10; // 默认6 | |||
// options.BaseTime = 1582206693000L; | |||
options.Method = method; | |||
options.WorkerId = 1; | |||
// options.TopOverCostCount=2000; | |||
// 首先测试一下 IdHelper 方法,获取单个Id | |||
YitIdHelper.setIdGenerator(options); | |||
@@ -38,7 +39,7 @@ public class StartUp { | |||
while (true) { | |||
genTest.GenStart(); | |||
Thread.sleep(1000); // 每隔1秒执行一次GenStart | |||
System.out.println("Hello World! Java"); | |||
// System.out.println("Hello World! Java"); | |||
} | |||
} catch (InterruptedException e) { | |||
e.printStackTrace(); | |||
@@ -1,18 +1,13 @@ | |||
// $Id$ | |||
// vim:ft=javascript | |||
// If your extension references something external, use ARG_WITH | |||
// ARG_WITH("snowdrift", "for snowdrift support", "no"); | |||
// Otherwise, use ARG_ENABLE | |||
ARG_ENABLE("snowdrift", "enable snowdrift support", "no"); | |||
ARG_ENABLE('snowdrift', 'snowdrift support', 'no'); | |||
if (PHP_SNOWDRIFT != "no") { | |||
AC_DEFINE('HAVE_SNOWDRIFT', 1, 'snowdrift support enabled'); | |||
snowdrift_source_file="snowdrift.c\ | |||
src/snowflake/snowflake.c\ | |||
src/snowflake/shm.c\ | |||
src/snowflake/spinlock.c | |||
" | |||
EXTENSION("snowdrift", $snowdrift_source_file, PHP_EXTNAME_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); | |||
src/snowflake/spinlock.c" | |||
EXTENSION("snowdrift", snowdrift_source_file, null, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); | |||
} | |||
@@ -66,9 +66,8 @@ static int snowdrift_init() | |||
shmctx.size = wid_num * sizeof(snowflake); | |||
if (shm_alloc(&shmctx) == -1) | |||
{ | |||
return FAILURE; | |||
return FAILURE; | |||
} | |||
bzero(shmctx.addr, wid_num * sizeof(snowflake)); | |||
sf = (snowflake *)shmctx.addr; | |||
int i; | |||
for (i = 0; i < wid_num; i++) | |||
@@ -92,7 +91,6 @@ static int snowdrift_init() | |||
{ | |||
return FAILURE; | |||
} | |||
bzero(shmctx.addr, sizeof(snowflake)); | |||
sf = (snowflake *)shmctx.addr; | |||
sf->Method = SD_G(Method); | |||
sf->BaseTime = SD_G(BaseTime); | |||
@@ -138,7 +136,7 @@ PHP_METHOD(snowdrift, NextNumId) | |||
{ | |||
zend_long num = 1; | |||
zend_long wid = SD_G(WorkerId); | |||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &num, &wid) == FAILURE) | |||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &num, &wid) == FAILURE) | |||
{ | |||
RETURN_FALSE; | |||
} | |||
@@ -1,65 +1,106 @@ | |||
#include <stdlib.h> | |||
#include <fcntl.h> | |||
#include <sys/types.h> | |||
#ifdef WIN32 | |||
#include "windows.h" | |||
#else | |||
#include <sys/mman.h> | |||
#include <strings.h> | |||
#endif | |||
#include "shm.h" | |||
#ifdef MAP_ANON | |||
#ifdef WIN32 | |||
#define NAME "SnowDrift" | |||
static HANDLE hMapFile; | |||
int shm_alloc(struct shm *shm) | |||
{ | |||
shm->addr = (void *)mmap(NULL, shm->size, | |||
PROT_READ | PROT_WRITE, | |||
MAP_ANONYMOUS | MAP_SHARED, -1, 0); | |||
int shm_alloc(struct shm* shm) { | |||
hMapFile = CreateFileMapping( | |||
INVALID_HANDLE_VALUE, | |||
NULL, | |||
PAGE_READWRITE, | |||
0, | |||
shm->size, | |||
NAME | |||
); | |||
if (hMapFile == NULL) | |||
{ | |||
return 0; | |||
} | |||
LPVOID pBuffer = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, shm->size); | |||
if (pBuffer == NULL) | |||
{ | |||
CloseHandle(hMapFile); | |||
return 0; | |||
} | |||
memset((char*)pBuffer, 0, shm->size); | |||
shm->addr = (void*)pBuffer; | |||
return 1; | |||
} | |||
void shm_free(struct shm* shm) { | |||
UnmapViewOfFile(shm->addr); | |||
CloseHandle(hMapFile); | |||
} | |||
if (shm->addr == NULL) | |||
{ | |||
return -1; | |||
} | |||
#elif defined(MAP_ANON) | |||
return 0; | |||
int shm_alloc(struct shm* shm) | |||
{ | |||
shm->addr = (void*)mmap(NULL, shm->size, | |||
PROT_READ | PROT_WRITE, | |||
MAP_ANONYMOUS | MAP_SHARED, -1, 0); | |||
if (shm->addr == NULL) | |||
{ | |||
return -1; | |||
} | |||
bzero(shm->addr, shm->size); | |||
return 0; | |||
} | |||
void shm_free(struct shm *shm) | |||
void shm_free(struct shm* shm) | |||
{ | |||
if (shm->addr) | |||
{ | |||
munmap((void *)shm->addr, shm->size); | |||
} | |||
if (shm->addr) | |||
{ | |||
munmap((void*)shm->addr, shm->size); | |||
} | |||
} | |||
#else | |||
int shm_alloc(struct shm *shm) | |||
int shm_alloc(struct shm* shm) | |||
{ | |||
int fd; | |||
fd = open("/dev/zero", O_RDWR); | |||
if (fd == -1) | |||
{ | |||
return -1; | |||
} | |||
int fd; | |||
shm->addr = (void *)mmap(NULL, shm->size, | |||
PROT_READ | PROT_WRITE, | |||
MAP_SHARED, fd, 0); | |||
fd = open("/dev/zero", O_RDWR); | |||
if (fd == -1) | |||
{ | |||
return -1; | |||
} | |||
close(fd); | |||
shm->addr = (void*)mmap(NULL, shm->size, | |||
PROT_READ | PROT_WRITE, | |||
MAP_SHARED, fd, 0); | |||
if (shm->addr == NULL) | |||
{ | |||
return -1; | |||
} | |||
close(fd); | |||
return 0; | |||
if (shm->addr == NULL) | |||
{ | |||
return -1; | |||
} | |||
bzero(shm->addr, shm->size); | |||
return 0; | |||
} | |||
void shm_free(struct shm *shm) | |||
void shm_free(struct shm* shm) | |||
{ | |||
if (shm->addr) | |||
{ | |||
munmap((void *)shm->addr, shm->size); | |||
} | |||
if (shm->addr) | |||
{ | |||
munmap((void*)shm->addr, shm->size); | |||
} | |||
} | |||
#endif |
@@ -1,14 +1,16 @@ | |||
#ifdef WIN32 | |||
#include "windows.h" | |||
#include <sys/timeb.h> | |||
#else | |||
#include <unistd.h> | |||
#include <sys/time.h> | |||
#include <time.h> | |||
#endif | |||
#include <stdlib.h> | |||
#include <stdio.h> | |||
#include "snowflake.h" | |||
#include "spinlock.h" | |||
#if defined(WIN32) | |||
#include "windows.h" | |||
#endif | |||
// static void EndOverCostAction(uint64_t useTimeTick, snowflake *flake); | |||
static inline uint64_t NextOverCostId(snowflake *flake); | |||
static inline uint64_t NextNormalId(snowflake *flake); | |||
@@ -16,7 +18,7 @@ static inline uint64_t GetCurrentTimeTick(snowflake *flake); | |||
static inline uint64_t GetNextTimeTick(snowflake *flake); | |||
static inline uint64_t CalcId(snowflake *flake); | |||
static inline uint64_t CalcTurnBackId(snowflake *flake); | |||
static inline uint64_t GetCurrentTime(); | |||
static inline uint64_t GetSysCurrentTime(); | |||
int ncpu; | |||
uint16_t spin = 2048; | |||
@@ -24,102 +26,103 @@ uint32_t pid = 0; | |||
void Config(snowflake *flake) | |||
{ | |||
if (pid == 0) | |||
{ | |||
pid = (uint32_t)getpid(); | |||
#if defined(WIN32) | |||
SYSTEM_INFO sysInfo; | |||
GetSystemInfo(&sysInfo); | |||
ncpu = sysInfo.dwNumberOfProcessors; | |||
if (pid == 0) | |||
{ | |||
#ifdef WIN32 | |||
pid = (uint32_t)GetCurrentProcessId(); | |||
SYSTEM_INFO sysInfo; | |||
GetSystemInfo(&sysInfo); | |||
ncpu = sysInfo.dwNumberOfProcessors; | |||
#else | |||
ncpu = sysconf(_SC_NPROCESSORS_ONLN); | |||
pid = (uint32_t)getpid(); | |||
ncpu = sysconf(_SC_NPROCESSORS_ONLN); | |||
#endif | |||
if (ncpu <= 0) | |||
{ | |||
ncpu = 1; | |||
} | |||
} | |||
if (flake->BaseTime == 0) | |||
{ | |||
flake->BaseTime = 1582136402000; | |||
} | |||
else if (flake->BaseTime < 631123200000 || flake->BaseTime > GetCurrentTime()) | |||
{ | |||
perror("BaseTime error."); | |||
exit(1); | |||
} | |||
if (ncpu <= 0) | |||
{ | |||
ncpu = 1; | |||
} | |||
} | |||
if (flake->BaseTime == 0) | |||
{ | |||
flake->BaseTime = 1582136402000; | |||
} | |||
else if (flake->BaseTime < 631123200000 || flake->BaseTime > GetSysCurrentTime()) | |||
{ | |||
perror("BaseTime error."); | |||
exit(1); | |||
} | |||
// 2.WorkerIdBitLength | |||
if (flake->WorkerIdBitLength <= 0) | |||
{ | |||
perror("WorkerIdBitLength error.(range:[1, 21])"); | |||
exit(1); | |||
} | |||
if (flake->SeqBitLength + flake->WorkerIdBitLength > 22) | |||
{ | |||
perror("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->WorkerIdBitLength = flake->WorkerIdBitLength <= 0 ? 6 : flake->WorkerIdBitLength; | |||
} | |||
// 2.WorkerIdBitLength | |||
if (flake->WorkerIdBitLength <= 0) | |||
{ | |||
perror("WorkerIdBitLength error.(range:[1, 21])"); | |||
exit(1); | |||
} | |||
if (flake->SeqBitLength + flake->WorkerIdBitLength > 22) | |||
{ | |||
perror("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->WorkerIdBitLength = flake->WorkerIdBitLength <= 0 ? 6 : flake->WorkerIdBitLength; | |||
} | |||
// 3.WorkerId | |||
uint32_t maxWorkerIdNumber = (1 << flake->WorkerIdBitLength) - 1; | |||
if (maxWorkerIdNumber == 0) | |||
{ | |||
maxWorkerIdNumber = 63; | |||
} | |||
if (flake->WorkerId < 0 || flake->WorkerId > maxWorkerIdNumber) | |||
{ | |||
perror("WorkerId error. (range:[0, {2^WorkerIdBitLength-1]}"); | |||
exit(1); | |||
} | |||
// 3.WorkerId | |||
uint32_t maxWorkerIdNumber = (1 << flake->WorkerIdBitLength) - 1; | |||
if (maxWorkerIdNumber == 0) | |||
{ | |||
maxWorkerIdNumber = 63; | |||
} | |||
if (flake->WorkerId < 0 || flake->WorkerId > maxWorkerIdNumber) | |||
{ | |||
perror("WorkerId error. (range:[0, {2^WorkerIdBitLength-1]}"); | |||
exit(1); | |||
} | |||
// 4.SeqBitLength | |||
if (flake->SeqBitLength < 2 || flake->SeqBitLength > 21) | |||
{ | |||
perror("SeqBitLength error. (range:[2, 21])"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->SeqBitLength = flake->SeqBitLength <= 0 ? 6 : flake->SeqBitLength; | |||
} | |||
// 4.SeqBitLength | |||
if (flake->SeqBitLength < 2 || flake->SeqBitLength > 21) | |||
{ | |||
perror("SeqBitLength error. (range:[2, 21])"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->SeqBitLength = flake->SeqBitLength <= 0 ? 6 : flake->SeqBitLength; | |||
} | |||
// 5.MaxSeqNumber | |||
uint32_t maxSeqNumber = (1 << flake->SeqBitLength) - 1; | |||
if (maxSeqNumber == 0) | |||
{ | |||
maxSeqNumber = 63; | |||
} | |||
if (flake->MaxSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MaxSeqNumber error. (range:[1, {2^SeqBitLength-1}]"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->MaxSeqNumber = flake->MaxSeqNumber <= 0 ? maxSeqNumber : flake->MaxSeqNumber; | |||
} | |||
// 5.MaxSeqNumber | |||
uint32_t maxSeqNumber = (1 << flake->SeqBitLength) - 1; | |||
if (maxSeqNumber == 0) | |||
{ | |||
maxSeqNumber = 63; | |||
} | |||
if (flake->MaxSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MaxSeqNumber error. (range:[1, {2^SeqBitLength-1}]"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->MaxSeqNumber = flake->MaxSeqNumber <= 0 ? maxSeqNumber : flake->MaxSeqNumber; | |||
} | |||
// 6.MinSeqNumber | |||
if (flake->MinSeqNumber < 5 || flake->MinSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MinSeqNumber error. (range:[5, {MinSeqNumber}]"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->MinSeqNumber = flake->MinSeqNumber <= 0 ? 5 : flake->MinSeqNumber; | |||
} | |||
// 6.MinSeqNumber | |||
if (flake->MinSeqNumber < 5 || flake->MinSeqNumber > maxSeqNumber) | |||
{ | |||
perror("MinSeqNumber error. (range:[5, {MinSeqNumber}]"); | |||
exit(1); | |||
} | |||
else | |||
{ | |||
flake->MinSeqNumber = flake->MinSeqNumber <= 0 ? 5 : flake->MinSeqNumber; | |||
} | |||
// 7.Others | |||
flake->TopOverCostCount = flake->TopOverCostCount <= 0 ? 2000 : flake->TopOverCostCount; | |||
flake->_TimestampShift = flake->WorkerIdBitLength + flake->SeqBitLength; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->Method = flake->Method; | |||
// 7.Others | |||
flake->TopOverCostCount = flake->TopOverCostCount <= 0 ? 2000 : flake->TopOverCostCount; | |||
flake->_TimestampShift = flake->WorkerIdBitLength + flake->SeqBitLength; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->Method = flake->Method; | |||
} | |||
// static inline void EndOverCostAction(uint64_t useTimeTick, snowflake *flake) | |||
@@ -132,158 +135,178 @@ void Config(snowflake *flake) | |||
static inline uint64_t NextOverCostId(snowflake *flake) | |||
{ | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (currentTimeTick > flake->_LastTimeTick) | |||
{ | |||
// EndOverCostAction(currentTimeTick, flake); | |||
flake->_LastTimeTick = currentTimeTick; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 0; | |||
flake->_OverCostCountInOneTerm = 0; | |||
// flake->_GenCountInOneTerm = 0; | |||
return CalcId(flake); | |||
} | |||
if (flake->_OverCostCountInOneTerm > flake->TopOverCostCount) | |||
{ | |||
// EndOverCostAction(currentTimeTick, flake); | |||
flake->_LastTimeTick = GetNextTimeTick(flake); | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 0; | |||
flake->_OverCostCountInOneTerm = 0; | |||
// flake->_GenCountInOneTerm = 0; | |||
return CalcId(flake); | |||
} | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
flake->_LastTimeTick++; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 1; | |||
flake->_OverCostCountInOneTerm++; | |||
// flake->_GenCountInOneTerm++; | |||
return CalcId(flake); | |||
} | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (currentTimeTick > flake->_LastTimeTick) | |||
{ | |||
// EndOverCostAction(currentTimeTick, flake); | |||
flake->_LastTimeTick = currentTimeTick; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 0; | |||
flake->_OverCostCountInOneTerm = 0; | |||
// flake->_GenCountInOneTerm = 0; | |||
return CalcId(flake); | |||
} | |||
if (flake->_OverCostCountInOneTerm > flake->TopOverCostCount) | |||
{ | |||
// EndOverCostAction(currentTimeTick, flake); | |||
flake->_LastTimeTick = GetNextTimeTick(flake); | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 0; | |||
flake->_OverCostCountInOneTerm = 0; | |||
// flake->_GenCountInOneTerm = 0; | |||
return CalcId(flake); | |||
} | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
flake->_LastTimeTick++; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 1; | |||
flake->_OverCostCountInOneTerm++; | |||
// flake->_GenCountInOneTerm++; | |||
return CalcId(flake); | |||
} | |||
// flake->_GenCountInOneTerm++; | |||
return CalcId(flake); | |||
// flake->_GenCountInOneTerm++; | |||
return CalcId(flake); | |||
} | |||
static inline uint64_t NextNormalId(snowflake *flake) | |||
{ | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (currentTimeTick < flake->_LastTimeTick) | |||
{ | |||
if (flake->_TurnBackTimeTick < 1) | |||
{ | |||
flake->_TurnBackTimeTick = flake->_LastTimeTick - 1; | |||
flake->_TurnBackIndex++; | |||
if (flake->_TurnBackIndex > 4) | |||
{ | |||
flake->_TurnBackIndex = 1; | |||
} | |||
} | |||
return CalcTurnBackId(flake); | |||
} | |||
if (flake->_TurnBackTimeTick > 0) | |||
{ | |||
flake->_TurnBackTimeTick = 0; | |||
} | |||
if (currentTimeTick > flake->_LastTimeTick) | |||
{ | |||
flake->_LastTimeTick = currentTimeTick; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
return CalcId(flake); | |||
} | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
// flake->_TermIndex++; | |||
flake->_LastTimeTick++; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 1; | |||
flake->_OverCostCountInOneTerm = 1; | |||
// flake->_GenCountInOneTerm = 1; | |||
return CalcId(flake); | |||
} | |||
return CalcId(flake); | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (currentTimeTick < flake->_LastTimeTick) | |||
{ | |||
if (flake->_TurnBackTimeTick < 1) | |||
{ | |||
flake->_TurnBackTimeTick = flake->_LastTimeTick - 1; | |||
flake->_TurnBackIndex++; | |||
if (flake->_TurnBackIndex > 4) | |||
{ | |||
flake->_TurnBackIndex = 1; | |||
} | |||
} | |||
return CalcTurnBackId(flake); | |||
} | |||
if (flake->_TurnBackTimeTick > 0) | |||
{ | |||
flake->_TurnBackTimeTick = 0; | |||
} | |||
if (currentTimeTick > flake->_LastTimeTick) | |||
{ | |||
flake->_LastTimeTick = currentTimeTick; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
return CalcId(flake); | |||
} | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
// flake->_TermIndex++; | |||
flake->_LastTimeTick++; | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
flake->_IsOverCost = 1; | |||
flake->_OverCostCountInOneTerm = 1; | |||
// flake->_GenCountInOneTerm = 1; | |||
return CalcId(flake); | |||
} | |||
return CalcId(flake); | |||
} | |||
static inline uint64_t GetCurrentTime() | |||
static inline uint64_t GetSysCurrentTime() | |||
{ | |||
struct timeval t; | |||
gettimeofday(&t, NULL); | |||
return (uint64_t)(t.tv_sec * 1000 + t.tv_usec / 1000); | |||
#ifdef WIN32 | |||
FILETIME file_time; | |||
GetSystemTimeAsFileTime(&file_time); | |||
uint64_t time = ((uint64_t)file_time.dwLowDateTime) + ((uint64_t)file_time.dwHighDateTime << 32); | |||
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); | |||
return (uint64_t)((time - EPOCH) / 10000LL); | |||
#else | |||
struct timeval t; | |||
gettimeofday(&t, NULL); | |||
return (uint64_t)(t.tv_sec * 1000 + t.tv_usec / 1000); | |||
#endif | |||
} | |||
static inline uint64_t GetCurrentTimeTick(snowflake *flake) | |||
{ | |||
return GetCurrentTime() - flake->BaseTime; | |||
return GetSysCurrentTime() - flake->BaseTime; | |||
} | |||
static inline uint64_t GetNextTimeTick(snowflake *flake) | |||
{ | |||
uint64_t tempTimeTicker = GetCurrentTimeTick(flake); | |||
while (tempTimeTicker <= flake->_LastTimeTick) | |||
{ | |||
tempTimeTicker = GetCurrentTimeTick(flake); | |||
} | |||
return tempTimeTicker; | |||
uint64_t tempTimeTicker = GetCurrentTimeTick(flake); | |||
struct timespec delay; | |||
delay.tv_sec = 0; | |||
delay.tv_nsec = 500000; | |||
while (1) | |||
{ | |||
tempTimeTicker = GetCurrentTimeTick(flake); | |||
if (tempTimeTicker > flake->_LastTimeTick) | |||
{ | |||
break; | |||
} | |||
#ifdef WIN32 | |||
SwitchToThread(); | |||
#else | |||
nanosleep(&delay, NULL); | |||
#endif | |||
} | |||
return tempTimeTicker; | |||
} | |||
static inline uint64_t CalcId(snowflake *flake) | |||
{ | |||
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_CurrentSeqNumber); | |||
flake->_CurrentSeqNumber++; | |||
return result; | |||
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_CurrentSeqNumber); | |||
flake->_CurrentSeqNumber++; | |||
return result; | |||
} | |||
static inline uint64_t CalcTurnBackId(snowflake *flake) | |||
{ | |||
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_TurnBackTimeTick); | |||
flake->_TurnBackTimeTick--; | |||
return result; | |||
uint64_t result = (flake->_LastTimeTick << flake->_TimestampShift) + (flake->WorkerId << flake->SeqBitLength) + (flake->_TurnBackTimeTick); | |||
flake->_TurnBackTimeTick--; | |||
return result; | |||
} | |||
static inline uint64_t NextSonwId(snowflake *flake) | |||
{ | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (flake->_LastTimeTick == currentTimeTick) | |||
{ | |||
flake->_CurrentSeqNumber++; | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
currentTimeTick = GetNextTimeTick(flake); | |||
} | |||
} | |||
else | |||
{ | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
} | |||
flake->_LastTimeTick = currentTimeTick; | |||
return (uint64_t)((currentTimeTick << flake->_TimestampShift) | (flake->WorkerId << flake->SeqBitLength) | flake->_CurrentSeqNumber); | |||
uint64_t currentTimeTick = GetCurrentTimeTick(flake); | |||
if (flake->_LastTimeTick == currentTimeTick) | |||
{ | |||
flake->_CurrentSeqNumber++; | |||
if (flake->_CurrentSeqNumber > flake->MaxSeqNumber) | |||
{ | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
currentTimeTick = GetNextTimeTick(flake); | |||
} | |||
} | |||
else | |||
{ | |||
flake->_CurrentSeqNumber = flake->MinSeqNumber; | |||
} | |||
flake->_LastTimeTick = currentTimeTick; | |||
return (uint64_t)((currentTimeTick << flake->_TimestampShift) | (flake->WorkerId << flake->SeqBitLength) | flake->_CurrentSeqNumber); | |||
} | |||
static inline uint64_t GetId(snowflake *flake) | |||
{ | |||
return flake->Method == 1 ? (flake->_IsOverCost != 0 ? NextOverCostId(flake) : NextNormalId(flake)) : NextSonwId(flake); | |||
return flake->Method == 1 ? (flake->_IsOverCost != 0 ? NextOverCostId(flake) : NextNormalId(flake)) : NextSonwId(flake); | |||
} | |||
uint64_t NextId(snowflake *flake) | |||
{ | |||
spin_lock(&flake->_Lock, pid); | |||
uint64_t id = GetId(flake); | |||
spin_unlock(&flake->_Lock, pid); | |||
return id; | |||
spin_lock(&flake->_Lock, pid); | |||
uint64_t id = GetId(flake); | |||
spin_unlock(&flake->_Lock, pid); | |||
return id; | |||
} | |||
uint64_t *NextNumId(snowflake *flake, uint32_t num) | |||
{ | |||
uint64_t *arr = (uint64_t *)malloc(sizeof(uint64_t) * num); | |||
spin_lock(&flake->_Lock, pid); | |||
uint32_t i; | |||
for (i = 0; i < num; i++) | |||
{ | |||
arr[i] = GetId(flake); | |||
} | |||
spin_unlock(&flake->_Lock, pid); | |||
return arr; | |||
uint64_t *arr = (uint64_t *)malloc(sizeof(uint64_t) * num); | |||
spin_lock(&flake->_Lock, pid); | |||
uint32_t i; | |||
for (i = 0; i < num; i++) | |||
{ | |||
arr[i] = GetId(flake); | |||
} | |||
spin_unlock(&flake->_Lock, pid); | |||
return arr; | |||
} |
@@ -1,47 +1,73 @@ | |||
#include <stdlib.h> | |||
#ifdef WIN32 | |||
#include "windows.h" | |||
#else | |||
#include <sched.h> | |||
#endif | |||
#include "spinlock.h" | |||
extern int ncpu; | |||
extern int spin; | |||
void spin_lock(atomic_t *lock, uint32_t pid) | |||
void spin_lock(atomic_t* lock, uint32_t pid) | |||
{ | |||
int i, n; | |||
for (;;) | |||
{ | |||
if (*lock == 0 && | |||
__sync_bool_compare_and_swap(lock, 0, pid)) | |||
{ | |||
return; | |||
} | |||
if (ncpu > 1) | |||
{ | |||
for (n = 1; n < spin; n <<= 1) | |||
{ | |||
for (i = 0; i < n; i++) | |||
{ | |||
__asm("pause"); | |||
} | |||
if (*lock == 0 && | |||
__sync_bool_compare_and_swap(lock, 0, pid)) | |||
{ | |||
return; | |||
} | |||
} | |||
} | |||
sched_yield(); | |||
} | |||
int i, n; | |||
for (;;) | |||
{ | |||
if (*lock == 0 && | |||
#ifdef WIN32 | |||
InterlockedCompareExchange(lock, pid, 0) == 0 | |||
#else | |||
__sync_bool_compare_and_swap(lock, 0, pid) | |||
#endif | |||
) | |||
{ | |||
return; | |||
} | |||
if (ncpu > 1) | |||
{ | |||
for (n = 1; n < spin; n <<= 1) | |||
{ | |||
for (i = 0; i < n; i++) | |||
{ | |||
#ifdef WIN32 | |||
MemoryBarrier(); | |||
#else | |||
__asm("pause"); | |||
#endif | |||
} | |||
if (*lock == 0 && | |||
#ifdef WIN32 | |||
InterlockedCompareExchange(lock, pid, 0) == 0 | |||
#else | |||
__sync_bool_compare_and_swap(lock, 0, pid) | |||
#endif | |||
) | |||
{ | |||
return; | |||
} | |||
} | |||
} | |||
#ifdef WIN32 | |||
SwitchToThread(); | |||
#else | |||
sched_yield(); | |||
#endif | |||
} | |||
} | |||
void spin_unlock(atomic_t *lock, uint32_t pid) | |||
void spin_unlock(atomic_t* lock, uint32_t pid) | |||
{ | |||
__sync_bool_compare_and_swap(lock, pid, 0); | |||
#ifdef WIN32 | |||
InterlockedCompareExchange(lock, 0, pid); | |||
#else | |||
__sync_bool_compare_and_swap(lock, pid, 0); | |||
#endif | |||
} |
@@ -0,0 +1,12 @@ | |||
# ❄ idgenerator-Python(未完成) | |||
## 运行环境 | |||
Python 3.6+ | |||
## 引用 包 | |||
## 调用示例 | |||
@@ -0,0 +1,31 @@ | |||
import time | |||
import traceback | |||
from IdGeneratorOptions import IdGeneratorOptions | |||
from SnowFlake import SnowFlake | |||
from SnowFlakeM1 import SnowFlakeM1 | |||
class DefaultIdGenerator(object): | |||
def SetIdGernerator(self, options) : | |||
if options.BaseTime < 100000 : | |||
raise ValueError ("BaseTime error.") | |||
self.SnowFlake= SnowFlakeM1(options) | |||
def NextId(self): | |||
return self.SnowFlake.NextId() | |||
if __name__ == '__main__': | |||
try: | |||
options = IdGeneratorOptions(23) | |||
options.BaseTime = 1231111111 | |||
idgen = DefaultIdGenerator() | |||
idgen.SetIdGernerator(options) | |||
print (idgen.NextId()) | |||
print (options.__dict__) | |||
except ValueError as e: | |||
print(e) | |||
@@ -0,0 +1,30 @@ | |||
import time | |||
class IdGeneratorOptions(object): | |||
def __init__(self, workerId = 0, workerIdBitLength = 6, seqBitLength = 6): | |||
# 雪花计算方法,(1-漂移算法|2-传统算法),默认1。目前只实现了1。 | |||
self.Method = 1 | |||
# 基础时间(ms单位),不能超过当前系统时间 | |||
self.BaseTime = 1288834974657 | |||
# 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1 | |||
self.WorkerId = workerId | |||
# 机器码位长,默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22) | |||
self.WorkerIdBitLength = workerIdBitLength | |||
# 序列数位长,默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22) | |||
self.SeqBitLength = seqBitLength | |||
# 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1]) | |||
self.MaxSeqNumber = 0 | |||
# 最小序列数(含),默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位 | |||
self.MinSeqNumber = 5 | |||
# 最大漂移次数(含),默认2000,推荐范围500-10000(与计算能力有关) | |||
self.TopOverCostCount = 2000 | |||
@@ -0,0 +1,11 @@ | |||
#!/usr/bin/python | |||
# coding=UTF-8 | |||
# 组件编号生成器 | |||
class SnowFlake(object): | |||
def __init__(self, options): | |||
self.Options = options | |||
def NextId(self): | |||
return 0 |
@@ -0,0 +1,12 @@ | |||
#!/usr/bin/python | |||
# coding=UTF-8 | |||
from SnowFlake import SnowFlake | |||
# 组件编号生成器 | |||
class SnowFlakeM1(SnowFlake): | |||
def __init__(self, options): | |||
self.Options = options | |||
def NextId(self): | |||
return self.Options.WorkerId |
@@ -222,9 +222,7 @@ QQ群:646049993 | |||
#### 动态库下载 | |||
下载链接1:https://github.com/yitter/IdGenerator/releases/download/reg_v1.0/regworkerid_lib_v1.0.zip | |||
下载链接2:https://gitee.com/yitter/idgenerator/attach_files/662372/download/regworkerid_lib_v1.0.zip | |||
下载链接1:https://github.com/yitter/IdGenerator/releases/download/v1.3.1/regworkerid_lib_v1.3.1.zip | |||
#### 动态库接口定义 | |||
``` | |||
@@ -27,6 +27,7 @@ bld/ | |||
**/.vs/ | |||
# Uncomment if you have tasks that create the project's static files in wwwroot | |||
#wwwroot/ | |||
.vscode | |||
# MSTest test Results | |||
[Tt]est[Rr]esult*/ | |||
@@ -254,4 +255,4 @@ paket-files/ | |||
target/ | |||
# macOS | |||
.DS_Store | |||
.DS_Store, |
@@ -2,10 +2,10 @@ | |||
* 版权属于:yitter(yitter@126.com) | |||
* 开源地址:https://github.com/yitter/idgenerator | |||
*/ | |||
use std::{thread}; | |||
use crate::idgen::*; | |||
use chrono::Utc; | |||
use std::thread; | |||
use std::thread::sleep; | |||
use crate::idgen::*; | |||
// use lazy_static::lazy_static; | |||
pub struct SnowWorkerM1 { | |||
@@ -42,26 +42,30 @@ impl SnowWorkerM1 { | |||
} | |||
pub fn SetOptions(&mut self, options: IdGeneratorOptions) { | |||
// 1.BaseTime | |||
if options.BaseTime == 0 { | |||
self.BaseTime = 1582136402000; | |||
} else if options.BaseTime < 631123200000 || options.BaseTime > Utc::now().timestamp_millis() { | |||
} else if options.BaseTime < 631123200000 | |||
|| options.BaseTime > Utc::now().timestamp_millis() | |||
{ | |||
panic!("BaseTime error."); | |||
} else { | |||
self.BaseTime = options.BaseTime; | |||
} | |||
// 2.WorkerIdBitLength | |||
if options.WorkerIdBitLength <= 0 | |||
{ | |||
if options.WorkerIdBitLength <= 0 { | |||
panic!("WorkerIdBitLength error.(range:[1, 21])"); | |||
} | |||
if options.SeqBitLength + options.WorkerIdBitLength > 22 { | |||
panic!("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||
} else { | |||
// self.WorkerIdBitLength = options.WorkerIdBitLength; | |||
self.WorkerIdBitLength = if options.WorkerIdBitLength <= 0 { 6 } else { options.WorkerIdBitLength }; | |||
self.WorkerIdBitLength = if options.WorkerIdBitLength <= 0 { | |||
6 | |||
} else { | |||
options.WorkerIdBitLength | |||
}; | |||
} | |||
// 3.WorkerId | |||
@@ -80,7 +84,11 @@ impl SnowWorkerM1 { | |||
panic!("SeqBitLength error. (range:[2, 21])"); | |||
} else { | |||
// self.SeqBitLength = options.SeqBitLength; | |||
self.SeqBitLength = if options.SeqBitLength <= 0 { 6 } else { options.SeqBitLength }; | |||
self.SeqBitLength = if options.SeqBitLength <= 0 { | |||
6 | |||
} else { | |||
options.SeqBitLength | |||
}; | |||
} | |||
// 5.MaxSeqNumber | |||
@@ -91,7 +99,11 @@ impl SnowWorkerM1 { | |||
if options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber { | |||
panic!("MaxSeqNumber error. (range:[1, {}]", maxSeqNumber); | |||
} else { | |||
self.MaxSeqNumber = if options.MaxSeqNumber == 0 { maxSeqNumber } else { options.MaxSeqNumber }; | |||
self.MaxSeqNumber = if options.MaxSeqNumber == 0 { | |||
maxSeqNumber | |||
} else { | |||
options.MaxSeqNumber | |||
}; | |||
} | |||
// 6.MinSeqNumber | |||
@@ -102,8 +114,15 @@ impl SnowWorkerM1 { | |||
// self.MinSeqNumber = if options.MinSeqNumber <= 0 { 5 } else { options.MinSeqNumber }; | |||
} | |||
// 7.Others | |||
self.TopOverCostCount = if options.TopOverCostCount == 0 { 2000 } else { options.TopOverCostCount }; | |||
// 7.TopOverCostCount | |||
//self.TopOverCostCount = if options.TopOverCostCount == 0 { 2000 } else { options.TopOverCostCount }; | |||
if options.TopOverCostCount < 0 || options.TopOverCostCount > 10000 { | |||
panic!("TopOverCostCount error. (range:[0, 10000]"); | |||
} else { | |||
self.TopOverCostCount = options.TopOverCostCount; | |||
} | |||
// 8.Others | |||
self._TimestampShift = self.WorkerIdBitLength + self.SeqBitLength; | |||
self._CurrentSeqNumber = self.MinSeqNumber; | |||
@@ -139,7 +158,11 @@ impl SnowWorkerM1 { | |||
pub fn NextId(&mut self) -> i64 { | |||
// println!("SeqBitLength: {}", self.SeqBitLength); | |||
if self._IsOverCost { self.NextOverCostId() } else { self.NextNormalId() } | |||
if self._IsOverCost { | |||
self.NextOverCostId() | |||
} else { | |||
self.NextNormalId() | |||
} | |||
} | |||
fn DoGenIdAction(&self, arg: OverCostActionArg) {} | |||
@@ -247,17 +270,17 @@ impl SnowWorkerM1 { | |||
} | |||
fn CalcId(&mut self, useTimeTick: i64) -> i64 { | |||
let result = (useTimeTick << self._TimestampShift) + | |||
(self.WorkerId << self.SeqBitLength) as i64 + | |||
(self._CurrentSeqNumber) as i64; | |||
let result = (useTimeTick << self._TimestampShift) | |||
+ (self.WorkerId << self.SeqBitLength) as i64 | |||
+ (self._CurrentSeqNumber) as i64; | |||
self._CurrentSeqNumber += 1; | |||
return result; | |||
} | |||
fn CalcTurnBackId(&mut self, useTimeTick: i64) -> i64 { | |||
let result = (useTimeTick << self._TimestampShift) + | |||
(self.WorkerId << self.SeqBitLength) as i64 + | |||
(self._TurnBackIndex) as i64; | |||
let result = (useTimeTick << self._TimestampShift) | |||
+ (self.WorkerId << self.SeqBitLength) as i64 | |||
+ (self._TurnBackIndex) as i64; | |||
self._TurnBackTimeTick -= 1; | |||
return result; | |||
} | |||
@@ -270,9 +293,11 @@ impl SnowWorkerM1 { | |||
let mut tempTimeTicker = self.GetCurrentTimeTick(); | |||
while tempTimeTicker <= self._LastTimeTick { | |||
// 暂停1ms | |||
sleep(std::time::Duration::from_millis(1)); | |||
tempTimeTicker = self.GetCurrentTimeTick(); | |||
} | |||
return tempTimeTicker; | |||
} | |||
} | |||
} |
@@ -1,16 +1,15 @@ | |||
mod idgen; | |||
use chrono::Utc; | |||
use idgen::*; | |||
use std::thread; | |||
use chrono::Utc; | |||
use std::time::Duration; | |||
fn main() { | |||
println!("Hello, world! Rust"); | |||
// 总执行次数 | |||
let times = 50000; | |||
let times = 500000; | |||
// 是否启用多线程测试 | |||
let multiThread = false; | |||
@@ -18,7 +17,7 @@ fn main() { | |||
// 全局设置一次运行参数 | |||
let mut options = IdGeneratorOptions::New(1); | |||
options.WorkerIdBitLength = 6; | |||
options.SeqBitLength = 6; | |||
options.SeqBitLength = 10; | |||
//... 可以继续设置其它 options 参数 | |||
YitIdHelper::SetIdGenerator(options); | |||
@@ -32,24 +31,29 @@ fn main() { | |||
while i < times { | |||
i += 1; | |||
if multiThread { // 这是多线程 | |||
thread::spawn(move || { | |||
id = YitIdHelper::NextId(); | |||
println!("{}, id: {}", i, id); | |||
}); | |||
} else { // 这是单线程 | |||
id = YitIdHelper::NextId(); | |||
} | |||
} | |||
YitIdHelper::NextId(); | |||
println!("最后生成的id: {}", id); | |||
if !multiThread { | |||
// 多线程情况下,时间统计不准确 | |||
let end = Utc::now().timestamp_millis(); | |||
println!("单线程用时 {} ms", end - start); | |||
// if multiThread { // 这是多线程 | |||
// thread::spawn(move || { | |||
// id = YitIdHelper::NextId(); | |||
// println!("{}, id: {}", i, id); | |||
// }); | |||
// } else { // 这是单线程 | |||
// id = YitIdHelper::NextId(); | |||
// } | |||
} | |||
thread::sleep(std::time::Duration::from_millis(2000)); | |||
let end = Utc::now().timestamp_millis(); | |||
println!("单线程用时 {} ms", end - start); | |||
// println!("最后生成的id: {}", id); | |||
// if !multiThread { | |||
// // 多线程情况下,时间统计不准确 | |||
// let end = Utc::now().timestamp_millis(); | |||
// println!("单线程用时 {} ms", end - start); | |||
// } | |||
thread::sleep(std::time::Duration::from_millis(1000)); | |||
} | |||
} | |||
@@ -71,6 +75,4 @@ fn set_redis() { | |||
// }, | |||
// Err(error) => println!("Unable to create Redis client: {}", error) | |||
// } | |||
} | |||
} |
@@ -68,14 +68,9 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; | |||
extern "C" { | |||
#endif | |||
extern __declspec(dllexport) void SetOptions(GoUint16 workerId); | |||
extern __declspec(dllexport) GoUint64 NextId(); | |||
// 注册一个 WorkerId,会先注销所有本机已注册的记录 | |||
extern __declspec(dllexport) GoInt32 RegisterOne(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId); | |||
// 注册多个 WorkerId,会先注销所有本机已注册的记录 | |||
extern __declspec(dllexport) int* RegisterMany(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId, GoInt32 totalCount); | |||
extern __declspec(dllexport) GoInt32 RegisterOne(char* ip, GoInt32 port, char* password, GoInt32 maxWorkerId, GoInt database); | |||
// 注销本机已注册的 WorkerId | |||
extern __declspec(dllexport) void UnRegister(); | |||