| @@ -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 | |||
| @@ -4,47 +4,19 @@ 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() | |||
| } | |||
| // 注册一个 WorkerId,会先注销所有本机已注册的记录 | |||
| //export RegisterOne | |||
| func RegisterOne(ip *C.char, port int32, password *C.char, maxWorkerId int32) int32 { | |||
| return regworkerid.RegisterOne(C.GoString(ip), port, C.GoString(password), maxWorkerId) | |||
| } | |||
| // 注册多个 WorkerId,会先注销所有本机已注册的记录 | |||
| ///export RegisterMany | |||
| func RegisterMany(ip *C.char, port int32, password *C.char, maxWorkerId int32, totalCount int32) []int32 { | |||
| //values := regworkerid.RegisterMany(C.GoString(ip), port, C.GoString(password), maxWorkerId, totalCount) | |||
| //return (*C.int)(unsafe.Pointer(&values)) | |||
| return regworkerid.RegisterMany(C.GoString(ip), port, C.GoString(password), maxWorkerId, totalCount) | |||
| } | |||
| // 注销本机已注册的 WorkerId | |||
| //export UnRegister | |||
| func UnRegister() { | |||
| regworkerid.UnRegister() | |||
| } | |||
| // 检查本地WorkerId是否有效(0-有效,其它-无效) | |||
| //export Validate | |||
| func Validate(workerId int32) int32 { | |||
| return regworkerid.Validate(workerId) | |||
| } | |||
| func main() { | |||
| const testGenId = true // 测试设置 | |||
| @@ -70,21 +42,36 @@ func main() { | |||
| time.Sleep(time.Duration(1000) * time.Millisecond) | |||
| } | |||
| } else { | |||
| workerIdList := regworkerid.RegisterMany("localhost", 6379, "", 4, 3) | |||
| // ip := "localhost" | |||
| ipChar := C.CString("localhost") | |||
| passChar := C.CString("") | |||
| workerIdList := RegisterMany(ipChar, 6379, passChar, 4, 3, 0) | |||
| for _, value := range workerIdList { | |||
| fmt.Println("注册的WorkerId:", value) | |||
| } | |||
| //var workerId = regworkerid.RegisterOne("localhost", 6379, "", 4) | |||
| //fmt.Println("注册的WorkerId:", workerId) | |||
| id := RegisterOne(ipChar, 6379, passChar, 4, 0) | |||
| fmt.Println("注册的WorkerId:", id) | |||
| // C.free(unsafe.Pointer(ipChar)) | |||
| // C.free(unsafe.Pointer(passChar)) | |||
| // var workerId = regworkerid.RegisterOne(ip, 6379, "", 4) | |||
| // fmt.Println("注册的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 | |||
| // 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,32 @@ | |||
| package main | |||
| import ( | |||
| "C" | |||
| ) | |||
| import "github.com/yitter/idgenerator-go/regworkerid" | |||
| //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) | |||
| } | |||
| // 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) | |||
| } | |||
| //export UnRegister | |||
| // 注销本机已注册的 WorkerId | |||
| func UnRegister() { | |||
| regworkerid.UnRegister() | |||
| } | |||
| //export Validate | |||
| // 检查本地WorkerId是否有效(0-有效,其它-无效) | |||
| func Validate(workerId int32) int32 { | |||
| return regworkerid.Validate(workerId) | |||
| } | |||
| @@ -3,15 +3,17 @@ | |||
| * 开源地址:https://github.com/yitter/idgenerator | |||
| */ | |||
| // Package regworkerid implements a simple distributed id generator. | |||
| package regworkerid | |||
| import ( | |||
| "context" | |||
| "fmt" | |||
| "github.com/go-redis/redis/v8" | |||
| "strconv" | |||
| "sync" | |||
| "time" | |||
| "github.com/go-redis/redis/v8" | |||
| ) | |||
| var _client *redis.Client | |||
| @@ -27,6 +29,7 @@ var _WorkerIdLifeTimeSeconds = 15 // IdGen:WorkerId:Value:xx 的值在 redis | |||
| var _MaxLoopCount = 10 // 最大循环次数(无可用WorkerId时循环查找) | |||
| var _SleepMillisecondEveryLoop = 200 // 每次循环后,暂停时间 | |||
| var _MaxWorkerId int32 = 0 // 最大WorkerId值,超过此值从0开始 | |||
| var _Database int = 0 // 最大WorkerId值,超过此值从0开始 | |||
| var _RedisConnString = "" | |||
| var _RedisPassword = "" | |||
| @@ -34,8 +37,10 @@ var _RedisPassword = "" | |||
| const _WorkerIdIndexKey string = "IdGen:WorkerId:Index" // redis 中的key | |||
| const _WorkerIdValueKeyPrefix string = "IdGen:WorkerId:Value:" // redis 中的key | |||
| const _WorkerIdFlag = "Y" // IdGen:WorkerId:Value:xx 的值(将来可用 _token 替代) | |||
| const _Log = false // 是否输出日志 | |||
| const _Log = false // 是否输出日志 | |||
| // export Validate | |||
| // 检查本地WorkerId是否有效(0-有效,其它-无效) | |||
| func Validate(workerId int32) int32 { | |||
| for _, value := range _workerIdList { | |||
| if value == workerId { | |||
| @@ -45,13 +50,15 @@ func Validate(workerId int32) int32 { | |||
| return 0 | |||
| //if workerId == _usingWorkerId { | |||
| // if workerId == _usingWorkerId { | |||
| // return 0 | |||
| //} else { | |||
| // } else { | |||
| // return -1 | |||
| //} | |||
| // } | |||
| } | |||
| // export UnRegister | |||
| // 注销本机已注册的 WorkerId | |||
| func UnRegister() { | |||
| _workerIdLock.Lock() | |||
| @@ -73,7 +80,7 @@ func autoUnRegister() { | |||
| } | |||
| } | |||
| func RegisterMany(ip string, port int32, password string, maxWorkerId int32, totalCount int32) []int32 { | |||
| func RegisterMany(ip string, port int32, password string, maxWorkerId int32, totalCount int32, database int) []int32 { | |||
| if maxWorkerId < 0 { | |||
| return []int32{-2} | |||
| } | |||
| @@ -87,6 +94,7 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||
| _MaxWorkerId = maxWorkerId | |||
| _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | |||
| _RedisPassword = password | |||
| _Database = database | |||
| _client = newRedisClient() | |||
| if _client == nil { | |||
| return []int32{-1} | |||
| @@ -96,15 +104,15 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||
| _ = _client.Close() | |||
| } | |||
| }() | |||
| //_, err := _client.Ping(_ctx).Result() | |||
| //if err != nil { | |||
| // _, err := _client.Ping(_ctx).Result() | |||
| // if err != nil { | |||
| // //panic("init redis error") | |||
| // return []int{-3} | |||
| //} else { | |||
| // } else { | |||
| // if _Log { | |||
| // fmt.Println("init redis ok") | |||
| // } | |||
| //} | |||
| // } | |||
| _lifeIndex++ | |||
| _workerIdList = make([]int32, totalCount) | |||
| @@ -117,7 +125,7 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||
| id := register(_lifeIndex) | |||
| if id > -1 { | |||
| useExtendFunc = true | |||
| _workerIdList[key] = id //= append(_workerIdList, id) | |||
| _workerIdList[key] = id // = append(_workerIdList, id) | |||
| } else { | |||
| break | |||
| } | |||
| @@ -130,7 +138,9 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||
| return _workerIdList | |||
| } | |||
| func RegisterOne(ip string, port int32, password string, maxWorkerId int32) int32 { | |||
| // export RegisterOne | |||
| // 注册一个 WorkerId,会先注销所有本机已注册的记录 | |||
| func RegisterOne(ip string, port int32, password string, maxWorkerId int32, database int) int32 { | |||
| if maxWorkerId < 0 { | |||
| return -2 | |||
| } | |||
| @@ -141,6 +151,7 @@ func RegisterOne(ip string, port int32, password string, maxWorkerId int32) int3 | |||
| _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | |||
| _RedisPassword = password | |||
| _loopCount = 0 | |||
| _Database = database | |||
| _client = newRedisClient() | |||
| if _client == nil { | |||
| return -3 | |||
| @@ -150,15 +161,15 @@ func RegisterOne(ip string, port int32, password string, maxWorkerId int32) int3 | |||
| _ = _client.Close() | |||
| } | |||
| }() | |||
| //_, err := _client.Ping(_ctx).Result() | |||
| //if err != nil { | |||
| // _, err := _client.Ping(_ctx).Result() | |||
| // if err != nil { | |||
| // // panic("init redis error") | |||
| // return -3 | |||
| //} else { | |||
| // } else { | |||
| // if _Log { | |||
| // fmt.Println("init redis ok") | |||
| // } | |||
| //} | |||
| // } | |||
| _lifeIndex++ | |||
| var id = register(_lifeIndex) | |||
| @@ -179,11 +190,11 @@ func newRedisClient() *redis.Client { | |||
| return redis.NewClient(&redis.Options{ | |||
| Addr: _RedisConnString, | |||
| Password: _RedisPassword, | |||
| DB: 0, | |||
| //PoolSize: 1000, | |||
| //ReadTimeout: time.Millisecond * time.Duration(100), | |||
| //WriteTimeout: time.Millisecond * time.Duration(100), | |||
| //IdleTimeout: time.Second * time.Duration(60), | |||
| DB: _Database, | |||
| // PoolSize: 1000, | |||
| // ReadTimeout: time.Millisecond * time.Duration(100), | |||
| // WriteTimeout: time.Millisecond * time.Duration(100), | |||
| // IdleTimeout: time.Second * time.Duration(60), | |||
| }) | |||
| } | |||
| @@ -310,9 +321,9 @@ func extendWorkerIdLifeTime(lifeIndex int, workerId int32) { | |||
| } | |||
| // 已经被注销,则终止(此步是上一步的二次验证) | |||
| //if _usingWorkerId < 0 { | |||
| // if _usingWorkerId < 0 { | |||
| // break | |||
| //} | |||
| // } | |||
| // 延长 redis 数据有效期 | |||
| extendWorkerIdFlag(myWorkerId) | |||