| @@ -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" | "C" | ||||
| "fmt" | "fmt" | ||||
| "time" | "time" | ||||
| "yitidgen/idgen" | |||||
| "yitidgen/regworkerid" | |||||
| "github.com/yitter/idgenerator-go/idgen" | |||||
| ) | ) | ||||
| //export SetOptions | |||||
| func SetOptions(workerId uint16) { | func SetOptions(workerId uint16) { | ||||
| var options = idgen.NewIdGeneratorOptions(workerId) | var options = idgen.NewIdGeneratorOptions(workerId) | ||||
| idgen.SetIdGenerator(options) | idgen.SetIdGenerator(options) | ||||
| } | } | ||||
| //export NextId | |||||
| func NextId() int64 { | func NextId() int64 { | ||||
| return idgen.NextId() | 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() { | func main() { | ||||
| const testGenId = true // 测试设置 | const testGenId = true // 测试设置 | ||||
| @@ -70,21 +42,36 @@ func main() { | |||||
| time.Sleep(time.Duration(1000) * time.Millisecond) | time.Sleep(time.Duration(1000) * time.Millisecond) | ||||
| } | } | ||||
| } else { | } 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 { | for _, value := range workerIdList { | ||||
| fmt.Println("注册的WorkerId:", value) | 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") | fmt.Println("end") | ||||
| time.Sleep(time.Duration(300) * time.Second) | time.Sleep(time.Duration(300) * time.Second) | ||||
| } | } | ||||
| } | } | ||||
| // To Build a dll/so: | |||||
| // windows: | // 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 | // 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 | * 开源地址:https://github.com/yitter/idgenerator | ||||
| */ | */ | ||||
| // Package regworkerid implements a simple distributed id generator. | |||||
| package regworkerid | package regworkerid | ||||
| import ( | import ( | ||||
| "context" | "context" | ||||
| "fmt" | "fmt" | ||||
| "github.com/go-redis/redis/v8" | |||||
| "strconv" | "strconv" | ||||
| "sync" | "sync" | ||||
| "time" | "time" | ||||
| "github.com/go-redis/redis/v8" | |||||
| ) | ) | ||||
| var _client *redis.Client | var _client *redis.Client | ||||
| @@ -27,6 +29,7 @@ var _WorkerIdLifeTimeSeconds = 15 // IdGen:WorkerId:Value:xx 的值在 redis | |||||
| var _MaxLoopCount = 10 // 最大循环次数(无可用WorkerId时循环查找) | var _MaxLoopCount = 10 // 最大循环次数(无可用WorkerId时循环查找) | ||||
| var _SleepMillisecondEveryLoop = 200 // 每次循环后,暂停时间 | var _SleepMillisecondEveryLoop = 200 // 每次循环后,暂停时间 | ||||
| var _MaxWorkerId int32 = 0 // 最大WorkerId值,超过此值从0开始 | var _MaxWorkerId int32 = 0 // 最大WorkerId值,超过此值从0开始 | ||||
| var _Database int = 0 // 最大WorkerId值,超过此值从0开始 | |||||
| var _RedisConnString = "" | var _RedisConnString = "" | ||||
| var _RedisPassword = "" | var _RedisPassword = "" | ||||
| @@ -34,8 +37,10 @@ var _RedisPassword = "" | |||||
| const _WorkerIdIndexKey string = "IdGen:WorkerId:Index" // redis 中的key | const _WorkerIdIndexKey string = "IdGen:WorkerId:Index" // redis 中的key | ||||
| const _WorkerIdValueKeyPrefix string = "IdGen:WorkerId:Value:" // redis 中的key | const _WorkerIdValueKeyPrefix string = "IdGen:WorkerId:Value:" // redis 中的key | ||||
| const _WorkerIdFlag = "Y" // IdGen:WorkerId:Value:xx 的值(将来可用 _token 替代) | const _WorkerIdFlag = "Y" // IdGen:WorkerId:Value:xx 的值(将来可用 _token 替代) | ||||
| const _Log = false // 是否输出日志 | |||||
| const _Log = false // 是否输出日志 | |||||
| // export Validate | |||||
| // 检查本地WorkerId是否有效(0-有效,其它-无效) | |||||
| func Validate(workerId int32) int32 { | func Validate(workerId int32) int32 { | ||||
| for _, value := range _workerIdList { | for _, value := range _workerIdList { | ||||
| if value == workerId { | if value == workerId { | ||||
| @@ -45,13 +50,15 @@ func Validate(workerId int32) int32 { | |||||
| return 0 | return 0 | ||||
| //if workerId == _usingWorkerId { | |||||
| // if workerId == _usingWorkerId { | |||||
| // return 0 | // return 0 | ||||
| //} else { | |||||
| // } else { | |||||
| // return -1 | // return -1 | ||||
| //} | |||||
| // } | |||||
| } | } | ||||
| // export UnRegister | |||||
| // 注销本机已注册的 WorkerId | |||||
| func UnRegister() { | func UnRegister() { | ||||
| _workerIdLock.Lock() | _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 { | if maxWorkerId < 0 { | ||||
| return []int32{-2} | return []int32{-2} | ||||
| } | } | ||||
| @@ -87,6 +94,7 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||||
| _MaxWorkerId = maxWorkerId | _MaxWorkerId = maxWorkerId | ||||
| _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | ||||
| _RedisPassword = password | _RedisPassword = password | ||||
| _Database = database | |||||
| _client = newRedisClient() | _client = newRedisClient() | ||||
| if _client == nil { | if _client == nil { | ||||
| return []int32{-1} | return []int32{-1} | ||||
| @@ -96,15 +104,15 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||||
| _ = _client.Close() | _ = _client.Close() | ||||
| } | } | ||||
| }() | }() | ||||
| //_, err := _client.Ping(_ctx).Result() | |||||
| //if err != nil { | |||||
| // _, err := _client.Ping(_ctx).Result() | |||||
| // if err != nil { | |||||
| // //panic("init redis error") | // //panic("init redis error") | ||||
| // return []int{-3} | // return []int{-3} | ||||
| //} else { | |||||
| // } else { | |||||
| // if _Log { | // if _Log { | ||||
| // fmt.Println("init redis ok") | // fmt.Println("init redis ok") | ||||
| // } | // } | ||||
| //} | |||||
| // } | |||||
| _lifeIndex++ | _lifeIndex++ | ||||
| _workerIdList = make([]int32, totalCount) | _workerIdList = make([]int32, totalCount) | ||||
| @@ -117,7 +125,7 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||||
| id := register(_lifeIndex) | id := register(_lifeIndex) | ||||
| if id > -1 { | if id > -1 { | ||||
| useExtendFunc = true | useExtendFunc = true | ||||
| _workerIdList[key] = id //= append(_workerIdList, id) | |||||
| _workerIdList[key] = id // = append(_workerIdList, id) | |||||
| } else { | } else { | ||||
| break | break | ||||
| } | } | ||||
| @@ -130,7 +138,9 @@ func RegisterMany(ip string, port int32, password string, maxWorkerId int32, tot | |||||
| return _workerIdList | 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 { | if maxWorkerId < 0 { | ||||
| return -2 | return -2 | ||||
| } | } | ||||
| @@ -141,6 +151,7 @@ func RegisterOne(ip string, port int32, password string, maxWorkerId int32) int3 | |||||
| _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | _RedisConnString = ip + ":" + strconv.Itoa(int(port)) | ||||
| _RedisPassword = password | _RedisPassword = password | ||||
| _loopCount = 0 | _loopCount = 0 | ||||
| _Database = database | |||||
| _client = newRedisClient() | _client = newRedisClient() | ||||
| if _client == nil { | if _client == nil { | ||||
| return -3 | return -3 | ||||
| @@ -150,15 +161,15 @@ func RegisterOne(ip string, port int32, password string, maxWorkerId int32) int3 | |||||
| _ = _client.Close() | _ = _client.Close() | ||||
| } | } | ||||
| }() | }() | ||||
| //_, err := _client.Ping(_ctx).Result() | |||||
| //if err != nil { | |||||
| // _, err := _client.Ping(_ctx).Result() | |||||
| // if err != nil { | |||||
| // // panic("init redis error") | // // panic("init redis error") | ||||
| // return -3 | // return -3 | ||||
| //} else { | |||||
| // } else { | |||||
| // if _Log { | // if _Log { | ||||
| // fmt.Println("init redis ok") | // fmt.Println("init redis ok") | ||||
| // } | // } | ||||
| //} | |||||
| // } | |||||
| _lifeIndex++ | _lifeIndex++ | ||||
| var id = register(_lifeIndex) | var id = register(_lifeIndex) | ||||
| @@ -179,11 +190,11 @@ func newRedisClient() *redis.Client { | |||||
| return redis.NewClient(&redis.Options{ | return redis.NewClient(&redis.Options{ | ||||
| Addr: _RedisConnString, | Addr: _RedisConnString, | ||||
| Password: _RedisPassword, | 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 | // break | ||||
| //} | |||||
| // } | |||||
| // 延长 redis 数据有效期 | // 延长 redis 数据有效期 | ||||
| extendWorkerIdFlag(myWorkerId) | extendWorkerIdFlag(myWorkerId) | ||||