From 4bd57ffa67b5c96a852176370134735751ce2899 Mon Sep 17 00:00:00 2001 From: lizhen Date: Mon, 30 Oct 2023 21:13:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- go.mod | 9 ++++--- go.sum | 3 ++- logic/idsequence/demo.go | 22 +++++++++++++++++ logic/idsequence/demo_test.go | 46 +++++++++++++++++++++++++++++++++++ logic/idsequence/sequence.go | 40 +++++++++++++----------------- 6 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 logic/idsequence/demo_test.go diff --git a/LICENSE b/LICENSE index 261eeb9..be9c08c 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [007lz] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/go.mod b/go.mod index 3dd7c19..7d6c92b 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,12 @@ go 1.20 require ( github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 github.com/gin-gonic/gin v1.9.1 + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/magiconair/properties v1.8.7 github.com/spf13/viper v1.17.0 + github.com/stretchr/testify v1.8.4 + google.golang.org/grpc v1.58.2 + google.golang.org/protobuf v1.31.0 gorm.io/driver/mysql v1.5.2 gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 ) @@ -14,6 +18,7 @@ require ( require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -23,7 +28,6 @@ require ( github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -35,6 +39,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -54,8 +59,6 @@ require ( golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect - google.golang.org/grpc v1.58.2 // indirect - google.golang.org/protobuf v1.31.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3c7d7ae..68c7efc 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -201,6 +202,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -532,7 +534,6 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= diff --git a/logic/idsequence/demo.go b/logic/idsequence/demo.go index cac7980..4e0a5a1 100644 --- a/logic/idsequence/demo.go +++ b/logic/idsequence/demo.go @@ -1,5 +1,10 @@ package idsequence +import ( + "context" + "fmt" +) + var IdSequenceMap = make(map[string]*IdSequence) func Init() { @@ -7,3 +12,20 @@ func Init() { "demo": NewIdSequence(10000, "demo"), } } + +func GetIdSequence(biz string) (*IdSequence, error) { + idSequence, ok := IdSequenceMap[biz] + if !ok { + return nil, fmt.Errorf("biz=(%s) nor support", biz) + } + + return idSequence, nil +} + +func Stop() { + for _, idSequence := range IdSequenceMap { + idSequence.stopMonitor <- true + idSequence.Close() + idSequence.saveLastId(context.Background()) + } +} diff --git a/logic/idsequence/demo_test.go b/logic/idsequence/demo_test.go new file mode 100644 index 0000000..a8d3852 --- /dev/null +++ b/logic/idsequence/demo_test.go @@ -0,0 +1,46 @@ +package idsequence + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestInit(t *testing.T) { + t.Run("case-normal", func(t *testing.T) { + Init() + fmt.Println("IdSequenceMap is: ", IdSequenceMap) + }) +} + +func TestGetIdSequence(t *testing.T) { + t.Run("case-success", func(t *testing.T) { + Init() + got, err := GetIdSequence("demo") + assert.Nil(t, err) + assert.Equal(t, got.biz, "demo") + }) + + t.Run("case-biz not support", func(t *testing.T) { + Init() + biz := "demo1" + got, err := GetIdSequence(biz) + assert.Equal(t, err, fmt.Errorf("biz=(%s) nor support", biz)) + assert.Nil(t, got) + }) +} + +func TestStop(t *testing.T) { + t.Run("case-normal", func(t *testing.T) { + Init() + + got, err := GetIdSequence("demo") + assert.Nil(t, err) + + Stop() + + _, ok := <-got.ids + assert.Equal(t, ok, false) + }) +} \ No newline at end of file diff --git a/logic/idsequence/sequence.go b/logic/idsequence/sequence.go index 25c03f6..a15395e 100644 --- a/logic/idsequence/sequence.go +++ b/logic/idsequence/sequence.go @@ -10,30 +10,15 @@ import ( "gitee.com/git-lz/go-tinyid/model" ) +// IdSequence - The generator struct type IdSequence struct { - idListLength int64 - biz string - ids chan int64 - stopMonitor chan bool -} - -func Stop() { - for _, idSequence := range IdSequenceMap { - idSequence.stopMonitor <- true - idSequence.Close() - idSequence.saveLastId(context.Background()) - } -} - -func GetIdSequence(biz string) (*IdSequence, error) { - idSequence, ok := IdSequenceMap[biz] - if !ok { - return nil, fmt.Errorf("biz=(%s) nor support", biz) - } - - return idSequence, nil + idListLength int64 // the length of id list, you can define it by your business + biz string // business type + ids chan int64 // the channel of id list + stopMonitor chan bool // the stop monitor signal } +// NewIdSequence - Create a new IdSequence by idListLength and biz func NewIdSequence(idListLength int64, biz string) *IdSequence { is := &IdSequence{ ids: make(chan int64, idListLength), @@ -46,11 +31,15 @@ func NewIdSequence(idListLength int64, biz string) *IdSequence { return is } +// Close - You can use it to close the id list channel and stop monitor goroutine func (is *IdSequence) Close() { close(is.ids) close(is.stopMonitor) } +// Monitor - This function can monitor the capacity of the id list. If the capacity of the id list is zero, it will +// +// add new ids to the list. func (is *IdSequence) Monitor(ctx context.Context) { for { select { @@ -69,8 +58,9 @@ func (is *IdSequence) Monitor(ctx context.Context) { } } +// GetOne - Get a new id from the id list channel. func (is *IdSequence) GetOne() (int64, error) { - // 如果取不到,则会等待1s + // if there is no new id, sleep 1s ticker := time.After(time.Second) for { @@ -85,6 +75,7 @@ func (is *IdSequence) GetOne() (int64, error) { } } +// add - Add new ids to the id list channel func (is *IdSequence) add(ctx context.Context) error { minId, maxId, err := is.getNewIdListLoop(ctx) if err != nil { @@ -98,6 +89,7 @@ func (is *IdSequence) add(ctx context.Context) error { return nil } +// getNewIdListLoop - Add new id to the id list channel for spin with optimistic lock. func (is *IdSequence) getNewIdListLoop(ctx context.Context) (int64, int64, error) { ticker := time.After(10 * time.Second) @@ -121,6 +113,7 @@ func (is *IdSequence) getNewIdListLoop(ctx context.Context) (int64, int64, error } } +// getNewIdListSync - Get new max id from the mysql with optimistic lock. func (is *IdSequence) getNewIdListSync(ctx context.Context, curMaxIdCh, newMaxIdCh chan int64, errCh chan error) { idSequenceDao := dao.NewIdSequenceDao() @@ -152,10 +145,11 @@ func (is *IdSequence) getNewIdListSync(ctx context.Context, curMaxIdCh, newMaxId record := records[0] newMaxId := record.Value + is.idListLength + version := record.Version + 1 rowsEffect, err := idSequenceDao.UpdateByCond(ctx, record.Version, map[string]interface{}{ "value": newMaxId, - "version": 0, + "version": version, }) if err != nil { errCh <- err -- Gitee