Compare commits

...

32 Commits

Author SHA1 Message Date
Kevin Wan
6deb80625d fix issue of default migrate version (#1536)
* fix issue of default migrate version

* chore: update console colors
2022-02-14 23:09:32 +08:00
Kevin Wan
6ab051568c Update readme-cn.md
add go-zero users
2022-02-14 16:57:48 +08:00
Kevin Wan
2732d3cdae chore: refactor cache (#1532) 2022-02-13 18:04:31 +08:00
chenquan
e8c307e4dc feat: support ctx in Cache (#1518)
* feature: support ctx in `Cache`

Signed-off-by: chenquan <chenquan.dev@foxmail.com>

* fix: `errors.Is` instead of `=`

Signed-off-by: chenquan <chenquan.dev@foxmail.com>
2022-02-13 17:28:14 +08:00
Kevin Wan
84ddc660c4 chore: goctl format issue (#1531) 2022-02-13 13:17:19 +08:00
Kevin Wan
e60e707955 upgrade grpc version (#1530) 2022-02-12 23:58:41 +08:00
Kevin Wan
cf4321b2d0 fix #1525 (#1527) 2022-02-11 23:04:57 +08:00
chenquan
1993faf2f8 fix: fix a typo (#1522)
Signed-off-by: chenquan <chenquan.dev@foxmail.com>
2022-02-11 21:15:45 +08:00
Kevin Wan
0ce85376bf chore: update goctl version to 1.3.2 (#1524) 2022-02-11 21:02:50 +08:00
Kevin Wan
a40254156f refactor: refactor yaml unmarshaler (#1517) 2022-02-09 17:22:52 +08:00
chenquan
05cc62f5ff chore: optimize yaml unmarshaler (#1513) 2022-02-09 16:57:00 +08:00
chenquan
9c2c90e533 chore: make error clearer (#1514) 2022-02-09 14:40:05 +08:00
Kevin Wan
822ee2e1c5 feat: update go-redis to v8, support ctx in redis methods (#1507)
* feat: update go-redis to v8, support ctx in redis methods

* fix compile errors

* chore: remove unused const

* chore: add tracing log on redis
2022-02-09 11:06:06 +08:00
anqiansong
77482c8946 fixes typo (#1511)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-08 22:16:38 +08:00
Kevin Wan
7ef0ab3119 Update readme-cn.md 2022-02-08 11:47:33 +08:00
anqiansong
8bd89a297a feature: Add goctl completion (#1505)
* feature: Add `goctl completion`

* Update const

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-08 10:50:21 +08:00
Kevin Wan
bb75cc796e test: change fuzz tests (#1504) 2022-02-05 09:44:01 +08:00
Kevin Wan
0fdd8f54eb ci: add test for win (#1503)
* ci: add test for win

* ci: update check names

* ci: use go build instead of go test to verify win test

* fix: windows test failure

* chore: disable logs in tests
2022-02-05 00:06:23 +08:00
anqiansong
b1ffc464cd fix typo: goctl protoc usage (#1502)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-02-03 22:13:02 +08:00
Kevin Wan
50174960e4 chore: update command comment (#1501) 2022-02-02 22:02:08 +08:00
Kevin Wan
8f46eab977 fix: goctl not compile on windows (#1500) 2022-02-01 13:58:08 +08:00
Kevin Wan
ec299085f5 docs: update tal-tech to zeromico in docs (#1498) 2022-02-01 13:03:30 +08:00
Kevin Wan
7727d70634 chore: update goctl version (#1497) 2022-02-01 09:50:26 +08:00
Kevin Wan
5f9d101bc6 feat: add runtime stats monitor (#1496) 2022-02-01 01:34:25 +08:00
Kevin Wan
6c2abe7474 fix: goroutine stuck on edge case (#1495)
* fix: goroutine stuck on edge case

* refactor: simplify mapreduce implementation
2022-01-30 13:09:21 +08:00
Kevin Wan
14a902c1a7 feat: handling panic in mapreduce, panic in calling goroutine, not inside goroutines (#1490)
* feat: handle panic

* chore: update fuzz test

* chore: optimize square sum algorithm
2022-01-28 10:59:41 +08:00
Kevin Wan
5ad6a6d229 Update readme-cn.md
add slogan
2022-01-27 17:16:30 +08:00
Kevin Wan
6f4b97864a chore: improve migrate confirmation (#1488) 2022-01-27 11:30:35 +08:00
Kevin Wan
0e0abc3a95 chore: update warning message (#1487) 2022-01-26 23:47:57 +08:00
anqiansong
696fda1db4 patch: goctl migrate (#1485)
* * Add signal check
* Add deprecated pkg check

* fix typo `replacementBuilderx`

* output to console if verbose

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-01-26 23:24:25 +08:00
Kevin Wan
c1d2634427 chore: update go version for goctl (#1484) 2022-01-26 14:27:43 +08:00
Kevin Wan
4b7a680ac5 refactor: rename from tal-tech to zeromicro for goctl (#1481) 2022-01-25 23:15:07 +08:00
196 changed files with 2764 additions and 1185 deletions

View File

@@ -7,32 +7,50 @@ on:
branches: [ master ] branches: [ master ]
jobs: jobs:
build: test-linux:
name: Build name: Linux
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
id: go
- name: Set up Go 1.x - name: Check out code into the Go module directory
uses: actions/setup-go@v2 uses: actions/checkout@v2
with:
go-version: ^1.15
id: go
- name: Check out code into the Go module directory - name: Get dependencies
uses: actions/checkout@v2 run: |
go get -v -t -d ./...
- name: Get dependencies - name: Lint
run: | run: |
go get -v -t -d ./... go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -s -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Lint - name: Test
run: | run: go test -race -coverprofile=coverage.txt -covermode=atomic ./...
go vet -stdmethods=false $(go list ./...)
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -s -l -extra .)" || echo "Please run 'gofumpt -l -w -extra .'"
- name: Test - name: Codecov
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./... uses: codecov/codecov-action@v2
- name: Codecov test-win:
uses: codecov/codecov-action@v2 name: Windows
runs-on: windows-latest
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.15
- name: Checkout codebase
uses: actions/checkout@v2
- name: Test
run: |
go mod verify
go mod download
go test -v -race ./...
cd tools/goctl && go build -v goctl.go

3
.gitignore vendored
View File

@@ -16,7 +16,8 @@
**/logs **/logs
# for test purpose # for test purpose
adhoc **/adhoc
**/testdata
# gitlab ci # gitlab ci
.cache .cache

View File

@@ -2,6 +2,13 @@ package discov
import "errors" import "errors"
var (
// errEmptyEtcdHosts indicates that etcd hosts are empty.
errEmptyEtcdHosts = errors.New("empty etcd hosts")
// errEmptyEtcdKey indicates that etcd key is empty.
errEmptyEtcdKey = errors.New("empty etcd key")
)
// EtcdConf is the config item with the given key on etcd. // EtcdConf is the config item with the given key on etcd.
type EtcdConf struct { type EtcdConf struct {
Hosts []string Hosts []string
@@ -27,9 +34,9 @@ func (c EtcdConf) HasTLS() bool {
// Validate validates c. // Validate validates c.
func (c EtcdConf) Validate() error { func (c EtcdConf) Validate() error {
if len(c.Hosts) == 0 { if len(c.Hosts) == 0 {
return errors.New("empty etcd hosts") return errEmptyEtcdHosts
} else if len(c.Key) == 0 { } else if len(c.Key) == 0 {
return errors.New("empty etcd key") return errEmptyEtcdKey
} else { } else {
return nil return nil
} }

View File

@@ -5,6 +5,9 @@ import (
"os" "os"
) )
// errExceedFileSize indicates that the file size is exceeded.
var errExceedFileSize = errors.New("exceed file size")
// A RangeReader is used to read a range of content from a file. // A RangeReader is used to read a range of content from a file.
type RangeReader struct { type RangeReader struct {
file *os.File file *os.File
@@ -29,7 +32,7 @@ func (rr *RangeReader) Read(p []byte) (n int, err error) {
} }
if rr.stop < rr.start || rr.start >= stat.Size() { if rr.stop < rr.start || rr.start >= stat.Size() {
return 0, errors.New("exceed file size") return 0, errExceedFileSize
} }
if rr.stop-rr.start < int64(len(p)) { if rr.stop-rr.start < int64(len(p)) {

View File

@@ -51,5 +51,5 @@ func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error {
} }
func formatError(v string, err error) error { func formatError(v string, err error) error {
return fmt.Errorf("string: `%s`, error: `%s`", v, err.Error()) return fmt.Errorf("string: `%s`, error: `%w`", v, err)
} }

View File

@@ -23,10 +23,9 @@ func TestPeriodLimit_RedisUnavailable(t *testing.T) {
const ( const (
seconds = 1 seconds = 1
total = 100
quota = 5 quota = 5
) )
l := NewPeriodLimit(seconds, quota, redis.NewRedis(s.Addr(), redis.NodeType), "periodlimit") l := NewPeriodLimit(seconds, quota, redis.New(s.Addr()), "periodlimit")
s.Close() s.Close()
val, err := l.Take("first") val, err := l.Take("first")
assert.NotNil(t, err) assert.NotNil(t, err)

View File

@@ -72,7 +72,7 @@ var (
// ErrLogServiceNameNotSet is an error that indicates that the service name is not set. // ErrLogServiceNameNotSet is an error that indicates that the service name is not set.
ErrLogServiceNameNotSet = errors.New("log service name must be set") ErrLogServiceNameNotSet = errors.New("log service name must be set")
timeFormat = "2006-01-02T15:04:05.000Z07" timeFormat = "2006-01-02T15:04:05.000Z07:00"
writeConsole bool writeConsole bool
logLevel uint32 logLevel uint32
encoding = jsonEncodingType encoding = jsonEncodingType

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
"io/ioutil"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@@ -14,7 +13,7 @@ const yamlTagKey = "json"
var ( var (
// ErrUnsupportedType is an error that indicates the config format is not supported. // ErrUnsupportedType is an error that indicates the config format is not supported.
ErrUnsupportedType = errors.New("only map-like configs are suported") ErrUnsupportedType = errors.New("only map-like configs are supported")
yamlUnmarshaler = NewUnmarshaler(yamlTagKey) yamlUnmarshaler = NewUnmarshaler(yamlTagKey)
) )
@@ -29,39 +28,6 @@ func UnmarshalYamlReader(reader io.Reader, v interface{}) error {
return unmarshalYamlReader(reader, v, yamlUnmarshaler) return unmarshalYamlReader(reader, v, yamlUnmarshaler)
} }
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
var o interface{}
if err := yamlUnmarshal(content, &o); err != nil {
return err
}
if m, ok := o.(map[string]interface{}); ok {
return unmarshaler.Unmarshal(m, v)
}
return ErrUnsupportedType
}
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
content, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
return unmarshalYamlBytes(content, v, unmarshaler)
}
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
func yamlUnmarshal(in []byte, out interface{}) error {
var res interface{}
if err := yaml.Unmarshal(in, &res); err != nil {
return err
}
*out.(*interface{}) = cleanupMapValue(res)
return nil
}
func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} { func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
res := make(map[string]interface{}) res := make(map[string]interface{})
for k, v := range in { for k, v := range in {
@@ -96,3 +62,40 @@ func cleanupMapValue(v interface{}) interface{} {
return Repr(v) return Repr(v)
} }
} }
func unmarshal(unmarshaler *Unmarshaler, o interface{}, v interface{}) error {
if m, ok := o.(map[string]interface{}); ok {
return unmarshaler.Unmarshal(m, v)
}
return ErrUnsupportedType
}
func unmarshalYamlBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error {
var o interface{}
if err := yamlUnmarshal(content, &o); err != nil {
return err
}
return unmarshal(unmarshaler, o, v)
}
func unmarshalYamlReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error {
var res interface{}
if err := yaml.NewDecoder(reader).Decode(&res); err != nil {
return err
}
return unmarshal(unmarshaler, cleanupMapValue(res), v)
}
// yamlUnmarshal YAML to map[string]interface{} instead of map[interface{}]interface{}.
func yamlUnmarshal(in []byte, out interface{}) error {
var res interface{}
if err := yaml.Unmarshal(in, &res); err != nil {
return err
}
*out.(*interface{}) = cleanupMapValue(res)
return nil
}

View File

@@ -926,14 +926,18 @@ func TestUnmarshalYamlBytesError(t *testing.T) {
} }
func TestUnmarshalYamlReaderError(t *testing.T) { func TestUnmarshalYamlReaderError(t *testing.T) {
payload := `abcd: cdef`
reader := strings.NewReader(payload)
var v struct { var v struct {
Any string Any string
} }
reader := strings.NewReader(`abcd: cdef`)
err := UnmarshalYamlReader(reader, &v) err := UnmarshalYamlReader(reader, &v)
assert.NotNil(t, err) assert.NotNil(t, err)
reader = strings.NewReader("chenquan")
err = UnmarshalYamlReader(reader, &v)
assert.ErrorIs(t, err, ErrUnsupportedType)
} }
func TestUnmarshalYamlBadReader(t *testing.T) { func TestUnmarshalYamlBadReader(t *testing.T) {
@@ -1011,6 +1015,6 @@ func TestUnmarshalYamlMapRune(t *testing.T) {
type badReader struct{} type badReader struct{}
func (b *badReader) Read(p []byte) (n int, err error) { func (b *badReader) Read(_ []byte) (n int, err error) {
return 0, io.ErrLimitReached return 0, io.ErrLimitReached
} }

View File

@@ -3,12 +3,11 @@ package mr
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"sync" "sync"
"sync/atomic"
"github.com/zeromicro/go-zero/core/errorx" "github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/lang" "github.com/zeromicro/go-zero/core/lang"
"github.com/zeromicro/go-zero/core/threading"
) )
const ( const (
@@ -42,6 +41,16 @@ type (
// Option defines the method to customize the mapreduce. // Option defines the method to customize the mapreduce.
Option func(opts *mapReduceOptions) Option func(opts *mapReduceOptions)
mapperContext struct {
ctx context.Context
mapper MapFunc
source <-chan interface{}
panicChan *onceChan
collector chan<- interface{}
doneChan <-chan lang.PlaceholderType
workers int
}
mapReduceOptions struct { mapReduceOptions struct {
ctx context.Context ctx context.Context
workers int workers int
@@ -90,46 +99,72 @@ func FinishVoid(fns ...func()) {
// ForEach maps all elements from given generate but no output. // ForEach maps all elements from given generate but no output.
func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) { func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
drain(Map(generate, func(item interface{}, writer Writer) {
mapper(item)
}, opts...))
}
// Map maps all elements generated from given generate func, and returns an output channel.
func Map(generate GenerateFunc, mapper MapFunc, opts ...Option) chan interface{} {
options := buildOptions(opts...) options := buildOptions(opts...)
source := buildSource(generate) panicChan := &onceChan{channel: make(chan interface{})}
source := buildSource(generate, panicChan)
collector := make(chan interface{}, options.workers) collector := make(chan interface{}, options.workers)
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
go executeMappers(options.ctx, mapper, source, collector, done, options.workers) go executeMappers(mapperContext{
ctx: options.ctx,
mapper: func(item interface{}, writer Writer) {
mapper(item)
},
source: source,
panicChan: panicChan,
collector: collector,
doneChan: done,
workers: options.workers,
})
return collector for {
select {
case v := <-panicChan.channel:
panic(v)
case _, ok := <-collector:
if !ok {
return
}
}
}
} }
// MapReduce maps all elements generated from given generate func, // MapReduce maps all elements generated from given generate func,
// and reduces the output elements with given reducer. // and reduces the output elements with given reducer.
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc, func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc,
opts ...Option) (interface{}, error) { opts ...Option) (interface{}, error) {
source := buildSource(generate) panicChan := &onceChan{channel: make(chan interface{})}
return MapReduceChan(source, mapper, reducer, opts...) source := buildSource(generate, panicChan)
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
} }
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer. // MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc, func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc,
opts ...Option) (interface{}, error) { opts ...Option) (interface{}, error) {
panicChan := &onceChan{channel: make(chan interface{})}
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
}
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapper MapperFunc,
reducer ReducerFunc, opts ...Option) (interface{}, error) {
options := buildOptions(opts...) options := buildOptions(opts...)
// output is used to write the final result
output := make(chan interface{}) output := make(chan interface{})
defer func() { defer func() {
// reducer can only write once, if more, panic
for range output { for range output {
panic("more than one element written in reducer") panic("more than one element written in reducer")
} }
}() }()
// collector is used to collect data from mapper, and consume in reducer
collector := make(chan interface{}, options.workers) collector := make(chan interface{}, options.workers)
// if done is closed, all mappers and reducer should stop processing
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
writer := newGuardedWriter(options.ctx, output, done) writer := newGuardedWriter(options.ctx, output, done)
var closeOnce sync.Once var closeOnce sync.Once
// use atomic.Value to avoid data race
var retErr errorx.AtomicError var retErr errorx.AtomicError
finish := func() { finish := func() {
closeOnce.Do(func() { closeOnce.Do(func() {
@@ -151,30 +186,38 @@ func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer Reducer
go func() { go func() {
defer func() { defer func() {
drain(collector) drain(collector)
if r := recover(); r != nil { if r := recover(); r != nil {
cancel(fmt.Errorf("%v", r)) panicChan.write(r)
} else {
finish()
} }
finish()
}() }()
reducer(collector, writer, cancel) reducer(collector, writer, cancel)
}() }()
go executeMappers(options.ctx, func(item interface{}, w Writer) { go executeMappers(mapperContext{
mapper(item, w, cancel) ctx: options.ctx,
}, source, collector, done, options.workers) mapper: func(item interface{}, w Writer) {
mapper(item, w, cancel)
},
source: source,
panicChan: panicChan,
collector: collector,
doneChan: done,
workers: options.workers,
})
select { select {
case <-options.ctx.Done(): case <-options.ctx.Done():
cancel(context.DeadlineExceeded) cancel(context.DeadlineExceeded)
return nil, context.DeadlineExceeded return nil, context.DeadlineExceeded
case value, ok := <-output: case v := <-panicChan.channel:
panic(v)
case v, ok := <-output:
if err := retErr.Load(); err != nil { if err := retErr.Load(); err != nil {
return nil, err return nil, err
} else if ok { } else if ok {
return value, nil return v, nil
} else { } else {
return nil, ErrReduceNoOutput return nil, ErrReduceNoOutput
} }
@@ -221,12 +264,18 @@ func buildOptions(opts ...Option) *mapReduceOptions {
return options return options
} }
func buildSource(generate GenerateFunc) chan interface{} { func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} {
source := make(chan interface{}) source := make(chan interface{})
threading.GoSafe(func() { go func() {
defer close(source) defer func() {
if r := recover(); r != nil {
panicChan.write(r)
}
close(source)
}()
generate(source) generate(source)
}) }()
return source return source
} }
@@ -238,39 +287,43 @@ func drain(channel <-chan interface{}) {
} }
} }
func executeMappers(ctx context.Context, mapper MapFunc, input <-chan interface{}, func executeMappers(mCtx mapperContext) {
collector chan<- interface{}, done <-chan lang.PlaceholderType, workers int) {
var wg sync.WaitGroup var wg sync.WaitGroup
defer func() { defer func() {
wg.Wait() wg.Wait()
close(collector) close(mCtx.collector)
drain(mCtx.source)
}() }()
pool := make(chan lang.PlaceholderType, workers) var failed int32
writer := newGuardedWriter(ctx, collector, done) pool := make(chan lang.PlaceholderType, mCtx.workers)
for { writer := newGuardedWriter(mCtx.ctx, mCtx.collector, mCtx.doneChan)
for atomic.LoadInt32(&failed) == 0 {
select { select {
case <-ctx.Done(): case <-mCtx.ctx.Done():
return return
case <-done: case <-mCtx.doneChan:
return return
case pool <- lang.Placeholder: case pool <- lang.Placeholder:
item, ok := <-input item, ok := <-mCtx.source
if !ok { if !ok {
<-pool <-pool
return return
} }
wg.Add(1) wg.Add(1)
// better to safely run caller defined method go func() {
threading.GoSafe(func() {
defer func() { defer func() {
if r := recover(); r != nil {
atomic.AddInt32(&failed, 1)
mCtx.panicChan.write(r)
}
wg.Done() wg.Done()
<-pool <-pool
}() }()
mapper(item, writer) mCtx.mapper(item, writer)
}) }()
} }
} }
} }
@@ -316,3 +369,16 @@ func (gw guardedWriter) Write(v interface{}) {
gw.channel <- v gw.channel <- v
} }
} }
type onceChan struct {
channel chan interface{}
wrote int32
}
func (oc *onceChan) write(val interface{}) {
if atomic.AddInt32(&oc.wrote, 1) > 1 {
return
}
oc.channel <- val
}

View File

@@ -0,0 +1,78 @@
//go:build go1.18
// +build go1.18
package mr
import (
"fmt"
"math/rand"
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.uber.org/goleak"
)
func FuzzMapReduce(f *testing.F) {
rand.Seed(time.Now().UnixNano())
f.Add(uint(10), uint(runtime.NumCPU()))
f.Fuzz(func(t *testing.T, num uint, workers uint) {
n := int64(num)%5000 + 5000
genPanic := rand.Intn(100) == 0
mapperPanic := rand.Intn(100) == 0
reducerPanic := rand.Intn(100) == 0
genIdx := rand.Int63n(n)
mapperIdx := rand.Int63n(n)
reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
return MapReduce(func(source chan<- interface{}) {
for i := int64(0); i < n; i++ {
source <- i
if genPanic && i == genIdx {
panic("foo")
}
}
}, func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx {
panic("bar")
}
writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var idx int64
var total int64
for v := range pipe {
if reducerPanic && idx == reducerIdx {
panic("baz")
}
total += v.(int64)
idx++
}
writer.Write(total)
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
}
if genPanic || mapperPanic || reducerPanic {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("n: %d", n))
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
assert.Panicsf(t, func() { fn() }, buf.String())
} else {
val, err := fn()
assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64))
}
})
}

View File

@@ -0,0 +1,107 @@
//go:build fuzz
// +build fuzz
package mr
import (
"fmt"
"math/rand"
"runtime"
"strconv"
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/threading"
"gopkg.in/cheggaaa/pb.v1"
)
// If Fuzz stuck, we don't know why, because it only returns hung or unexpected,
// so we need to simulate the fuzz test in test mode.
func TestMapReduceRandom(t *testing.T) {
rand.Seed(time.Now().UnixNano())
const (
times = 10000
nRange = 500
mega = 1024 * 1024
)
bar := pb.New(times).Start()
runner := threading.NewTaskRunner(runtime.NumCPU())
var wg sync.WaitGroup
wg.Add(times)
for i := 0; i < times; i++ {
runner.Schedule(func() {
start := time.Now()
defer func() {
if time.Since(start) > time.Minute {
t.Fatal("timeout")
}
wg.Done()
}()
t.Run(strconv.Itoa(i), func(t *testing.T) {
n := rand.Int63n(nRange)%nRange + nRange
workers := rand.Int()%50 + runtime.NumCPU()/2
genPanic := rand.Intn(100) == 0
mapperPanic := rand.Intn(100) == 0
reducerPanic := rand.Intn(100) == 0
genIdx := rand.Int63n(n)
mapperIdx := rand.Int63n(n)
reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) {
return MapReduce(func(source chan<- interface{}) {
for i := int64(0); i < n; i++ {
source <- i
if genPanic && i == genIdx {
panic("foo")
}
}
}, func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx {
panic("bar")
}
writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var idx int64
var total int64
for v := range pipe {
if reducerPanic && idx == reducerIdx {
panic("baz")
}
total += v.(int64)
idx++
}
writer.Write(total)
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2))
}
if genPanic || mapperPanic || reducerPanic {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("n: %d", n))
buf.WriteString(fmt.Sprintf(", genPanic: %t", genPanic))
buf.WriteString(fmt.Sprintf(", mapperPanic: %t", mapperPanic))
buf.WriteString(fmt.Sprintf(", reducerPanic: %t", reducerPanic))
buf.WriteString(fmt.Sprintf(", genIdx: %d", genIdx))
buf.WriteString(fmt.Sprintf(", mapperIdx: %d", mapperIdx))
buf.WriteString(fmt.Sprintf(", reducerIdx: %d", reducerIdx))
assert.Panicsf(t, func() { fn() }, buf.String())
} else {
val, err := fn()
assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64))
}
bar.Increment()
})
})
}
wg.Wait()
bar.Finish()
}

View File

@@ -11,8 +11,6 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stringx"
"github.com/zeromicro/go-zero/core/syncx"
"go.uber.org/goleak" "go.uber.org/goleak"
) )
@@ -124,84 +122,69 @@ func TestForEach(t *testing.T) {
t.Run("all", func(t *testing.T) { t.Run("all", func(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
ForEach(func(source chan<- interface{}) { assert.PanicsWithValue(t, "foo", func() {
for i := 0; i < tasks; i++ { ForEach(func(source chan<- interface{}) {
source <- i for i := 0; i < tasks; i++ {
} source <- i
}, func(item interface{}) { }
panic("foo") }, func(item interface{}) {
panic("foo")
})
}) })
}) })
} }
func TestMap(t *testing.T) { func TestGeneratePanic(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
tests := []struct { t.Run("all", func(t *testing.T) {
mapper MapFunc assert.PanicsWithValue(t, "foo", func() {
expect int ForEach(func(source chan<- interface{}) {
}{ panic("foo")
{ }, func(item interface{}) {
mapper: func(item interface{}, writer Writer) { })
v := item.(int) })
writer.Write(v * v) })
}, }
expect: 30,
},
{
mapper: func(item interface{}, writer Writer) {
v := item.(int)
if v%2 == 0 {
return
}
writer.Write(v * v)
},
expect: 10,
},
{
mapper: func(item interface{}, writer Writer) {
v := item.(int)
if v%2 == 0 {
panic(v)
}
writer.Write(v * v)
},
expect: 10,
},
}
for _, test := range tests { func TestMapperPanic(t *testing.T) {
t.Run(stringx.Rand(), func(t *testing.T) { defer goleak.VerifyNone(t)
channel := Map(func(source chan<- interface{}) {
for i := 1; i < 5; i++ { const tasks = 1000
var run int32
t.Run("all", func(t *testing.T) {
assert.PanicsWithValue(t, "foo", func() {
_, _ = MapReduce(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i source <- i
} }
}, test.mapper, WithWorkers(-1)) }, func(item interface{}, writer Writer, cancel func(error)) {
atomic.AddInt32(&run, 1)
var result int panic("foo")
for v := range channel { }, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
result += v.(int) })
}
assert.Equal(t, test.expect, result)
}) })
} assert.True(t, atomic.LoadInt32(&run) < tasks/2)
})
} }
func TestMapReduce(t *testing.T) { func TestMapReduce(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
tests := []struct { tests := []struct {
name string
mapper MapperFunc mapper MapperFunc
reducer ReducerFunc reducer ReducerFunc
expectErr error expectErr error
expectValue interface{} expectValue interface{}
}{ }{
{ {
name: "simple",
expectErr: nil, expectErr: nil,
expectValue: 30, expectValue: 30,
}, },
{ {
name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int) v := item.(int)
if v%3 == 0 { if v%3 == 0 {
@@ -212,6 +195,7 @@ func TestMapReduce(t *testing.T) {
expectErr: errDummy, expectErr: errDummy,
}, },
{ {
name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int) v := item.(int)
if v%3 == 0 { if v%3 == 0 {
@@ -223,6 +207,7 @@ func TestMapReduce(t *testing.T) {
expectValue: nil, expectValue: nil,
}, },
{ {
name: "cancel with more",
reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) { reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int var result int
for item := range pipe { for item := range pipe {
@@ -237,45 +222,68 @@ func TestMapReduce(t *testing.T) {
}, },
} }
for _, test := range tests { t.Run("MapReduce", func(t *testing.T) {
t.Run(stringx.Rand(), func(t *testing.T) { for _, test := range tests {
if test.mapper == nil { t.Run(test.name, func(t *testing.T) {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) { if test.mapper == nil {
v := item.(int) test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
writer.Write(v * v) v := item.(int)
} writer.Write(v * v)
}
if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
result += item.(int)
} }
writer.Write(result)
} }
} if test.reducer == nil {
value, err := MapReduce(func(source chan<- interface{}) { test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
for i := 1; i < 5; i++ { var result int
source <- i for item := range pipe {
result += item.(int)
}
writer.Write(result)
}
} }
}, test.mapper, test.reducer, WithWorkers(runtime.NumCPU())) value, err := MapReduce(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
source <- i
}
}, test.mapper, test.reducer, WithWorkers(runtime.NumCPU()))
assert.Equal(t, test.expectErr, err) assert.Equal(t, test.expectErr, err)
assert.Equal(t, test.expectValue, value) assert.Equal(t, test.expectValue, value)
}) })
} }
} })
func TestMapReducePanicBothMapperAndReducer(t *testing.T) { t.Run("MapReduce", func(t *testing.T) {
defer goleak.VerifyNone(t) for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int)
writer.Write(v * v)
}
}
if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
var result int
for item := range pipe {
result += item.(int)
}
writer.Write(result)
}
}
_, _ = MapReduce(func(source chan<- interface{}) { source := make(chan interface{})
source <- 0 go func() {
source <- 1 for i := 1; i < 5; i++ {
}, func(item interface{}, writer Writer, cancel func(error)) { source <- i
panic("foo") }
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { close(source)
panic("bar") }()
value, err := MapReduceChan(source, test.mapper, test.reducer, WithWorkers(-1))
assert.Equal(t, test.expectErr, err)
assert.Equal(t, test.expectValue, value)
})
}
}) })
} }
@@ -302,16 +310,19 @@ func TestMapReduceVoid(t *testing.T) {
var value uint32 var value uint32
tests := []struct { tests := []struct {
name string
mapper MapperFunc mapper MapperFunc
reducer VoidReducerFunc reducer VoidReducerFunc
expectValue uint32 expectValue uint32
expectErr error expectErr error
}{ }{
{ {
name: "simple",
expectValue: 30, expectValue: 30,
expectErr: nil, expectErr: nil,
}, },
{ {
name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int) v := item.(int)
if v%3 == 0 { if v%3 == 0 {
@@ -322,6 +333,7 @@ func TestMapReduceVoid(t *testing.T) {
expectErr: errDummy, expectErr: errDummy,
}, },
{ {
name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(item interface{}, writer Writer, cancel func(error)) {
v := item.(int) v := item.(int)
if v%3 == 0 { if v%3 == 0 {
@@ -332,6 +344,7 @@ func TestMapReduceVoid(t *testing.T) {
expectErr: ErrCancelWithNil, expectErr: ErrCancelWithNil,
}, },
{ {
name: "cancel with more",
reducer: func(pipe <-chan interface{}, cancel func(error)) { reducer: func(pipe <-chan interface{}, cancel func(error)) {
for item := range pipe { for item := range pipe {
result := atomic.AddUint32(&value, uint32(item.(int))) result := atomic.AddUint32(&value, uint32(item.(int)))
@@ -345,7 +358,7 @@ func TestMapReduceVoid(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
atomic.StoreUint32(&value, 0) atomic.StoreUint32(&value, 0)
if test.mapper == nil { if test.mapper == nil {
@@ -400,39 +413,59 @@ func TestMapReduceVoidWithDelay(t *testing.T) {
assert.Equal(t, 0, result[1]) assert.Equal(t, 0, result[1])
} }
func TestMapVoid(t *testing.T) {
defer goleak.VerifyNone(t)
const tasks = 1000
var count uint32
ForEach(func(source chan<- interface{}) {
for i := 0; i < tasks; i++ {
source <- i
}
}, func(item interface{}) {
atomic.AddUint32(&count, 1)
})
assert.Equal(t, tasks, int(count))
}
func TestMapReducePanic(t *testing.T) { func TestMapReducePanic(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
v, err := MapReduce(func(source chan<- interface{}) { assert.Panics(t, func() {
source <- 0 _, _ = MapReduce(func(source chan<- interface{}) {
source <- 1 source <- 0
}, func(item interface{}, writer Writer, cancel func(error)) { source <- 1
i := item.(int) }, func(item interface{}, writer Writer, cancel func(error)) {
writer.Write(i) i := item.(int)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { writer.Write(i)
for range pipe { }, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
panic("panic") for range pipe {
} panic("panic")
}
})
})
}
func TestMapReducePanicOnce(t *testing.T) {
defer goleak.VerifyNone(t)
assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) {
for i := 0; i < 100; i++ {
source <- i
}
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
if i == 0 {
panic("foo")
}
writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
for range pipe {
panic("bar")
}
})
})
}
func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
defer goleak.VerifyNone(t)
assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) {
source <- 0
source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) {
panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) {
panic("bar")
})
}) })
assert.Nil(t, v)
assert.NotNil(t, err)
assert.Equal(t, "panic", err.Error())
} }
func TestMapReduceVoidCancel(t *testing.T) { func TestMapReduceVoidCancel(t *testing.T) {
@@ -461,13 +494,13 @@ func TestMapReduceVoidCancel(t *testing.T) {
func TestMapReduceVoidCancelWithRemains(t *testing.T) { func TestMapReduceVoidCancelWithRemains(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var done syncx.AtomicBool var done int32
var result []int var result []int
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
done.Set(true) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int) i := item.(int)
if i == defaultWorkers/2 { if i == defaultWorkers/2 {
@@ -482,7 +515,7 @@ func TestMapReduceVoidCancelWithRemains(t *testing.T) {
}) })
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, "anything", err.Error()) assert.Equal(t, "anything", err.Error())
assert.True(t, done.True()) assert.Equal(t, int32(1), done)
} }
func TestMapReduceWithoutReducerWrite(t *testing.T) { func TestMapReduceWithoutReducerWrite(t *testing.T) {
@@ -507,34 +540,51 @@ func TestMapReduceVoidPanicInReducer(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
const message = "foo" const message = "foo"
var done syncx.AtomicBool assert.Panics(t, func() {
err := MapReduceVoid(func(source chan<- interface{}) { var done int32
_ = MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) {
panic(message)
}, WithWorkers(1))
})
}
func TestForEachWithContext(t *testing.T) {
defer goleak.VerifyNone(t)
var done int32
ctx, cancel := context.WithCancel(context.Background())
ForEach(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
done.Set(true) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item interface{}) {
i := item.(int) i := item.(int)
writer.Write(i) if i == defaultWorkers/2 {
}, func(pipe <-chan interface{}, cancel func(error)) { cancel()
panic(message) }
}, WithWorkers(1)) }, WithContext(ctx))
assert.NotNil(t, err)
assert.Equal(t, message, err.Error())
assert.True(t, done.True())
} }
func TestMapReduceWithContext(t *testing.T) { func TestMapReduceWithContext(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var done syncx.AtomicBool var done int32
var result []int var result []int
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
done.Set(true) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, c func(error)) { }, func(item interface{}, writer Writer, c func(error)) {
i := item.(int) i := item.(int)
if i == defaultWorkers/2 { if i == defaultWorkers/2 {

View File

@@ -54,7 +54,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/tal-tech/go-zero/core/mr" "github.com/zeromicro/go-zero/core/mr"
) )
func main() { func main() {

View File

@@ -55,7 +55,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/tal-tech/go-zero/core/mr" "github.com/zeromicro/go-zero/core/mr"
) )
func main() { func main() {
@@ -87,4 +87,4 @@ More examples: [https://github.com/zeromicro/zero-examples/tree/main/mapreduce](
## Give a Star! ⭐ ## Give a Star! ⭐
If you like or are using this project to learn or start your solution, please give it a star. Thanks! If you like or are using this project to learn or start your solution, please give it a star. Thanks!

View File

@@ -1,3 +1,6 @@
//go:build linux || darwin
// +build linux darwin
package proc package proc
import ( import (

30
core/prof/runtime.go Normal file
View File

@@ -0,0 +1,30 @@
package prof
import (
"fmt"
"runtime"
"time"
)
const (
defaultInterval = time.Second * 5
mega = 1024 * 1024
)
func DisplayStats(interval ...time.Duration) {
duration := defaultInterval
for _, val := range interval {
duration = val
}
go func() {
ticker := time.NewTicker(duration)
defer ticker.Stop()
for range ticker.C {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Goroutines: %d, Alloc: %vm, TotalAlloc: %vm, Sys: %vm, NumGC: %v\n",
runtime.NumGoroutine(), m.Alloc/mega, m.TotalAlloc/mega, m.Sys/mega, m.NumGC)
}
}()
}

View File

@@ -1,6 +1,8 @@
package cache package cache
import ( import (
"context"
"errors"
"fmt" "fmt"
"log" "log"
"time" "time"
@@ -13,13 +15,37 @@ import (
type ( type (
// Cache interface is used to define the cache implementation. // Cache interface is used to define the cache implementation.
Cache interface { Cache interface {
// Del deletes cached values with keys.
Del(keys ...string) error Del(keys ...string) error
Get(key string, v interface{}) error // DelCtx deletes cached values with keys.
DelCtx(ctx context.Context, keys ...string) error
// Get gets the cache with key and fills into v.
Get(key string, val interface{}) error
// GetCtx gets the cache with key and fills into v.
GetCtx(ctx context.Context, key string, val interface{}) error
// IsNotFound checks if the given error is the defined errNotFound.
IsNotFound(err error) bool IsNotFound(err error) bool
Set(key string, v interface{}) error // Set sets the cache with key and v, using c.expiry.
SetWithExpire(key string, v interface{}, expire time.Duration) error Set(key string, val interface{}) error
Take(v interface{}, key string, query func(v interface{}) error) error // SetCtx sets the cache with key and v, using c.expiry.
TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error SetCtx(ctx context.Context, key string, val interface{}) error
// SetWithExpire sets the cache with key and v, using given expire.
SetWithExpire(key string, val interface{}, expire time.Duration) error
// SetWithExpireCtx sets the cache with key and v, using given expire.
SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error
// Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
Take(val interface{}, key string, query func(val interface{}) error) error
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error
// TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
TakeWithExpireCtx(ctx context.Context, val interface{}, key string,
query func(val interface{}, expire time.Duration) error) error
} }
cacheCluster struct { cacheCluster struct {
@@ -51,7 +77,13 @@ func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
} }
} }
// Del deletes cached values with keys.
func (cc cacheCluster) Del(keys ...string) error { func (cc cacheCluster) Del(keys ...string) error {
return cc.DelCtx(context.Background(), keys...)
}
// DelCtx deletes cached values with keys.
func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error {
switch len(keys) { switch len(keys) {
case 0: case 0:
return nil return nil
@@ -62,7 +94,7 @@ func (cc cacheCluster) Del(keys ...string) error {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).Del(key) return c.(Cache).DelCtx(ctx, key)
default: default:
var be errorx.BatchError var be errorx.BatchError
nodes := make(map[interface{}][]string) nodes := make(map[interface{}][]string)
@@ -76,7 +108,7 @@ func (cc cacheCluster) Del(keys ...string) error {
nodes[c] = append(nodes[c], key) nodes[c] = append(nodes[c], key)
} }
for c, ks := range nodes { for c, ks := range nodes {
if err := c.(Cache).Del(ks...); err != nil { if err := c.(Cache).DelCtx(ctx, ks...); err != nil {
be.Add(err) be.Add(err)
} }
} }
@@ -85,52 +117,86 @@ func (cc cacheCluster) Del(keys ...string) error {
} }
} }
func (cc cacheCluster) Get(key string, v interface{}) error { // Get gets the cache with key and fills into v.
func (cc cacheCluster) Get(key string, val interface{}) error {
return cc.GetCtx(context.Background(), key, val)
}
// GetCtx gets the cache with key and fills into v.
func (cc cacheCluster) GetCtx(ctx context.Context, key string, val interface{}) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).Get(key, v) return c.(Cache).GetCtx(ctx, key, val)
} }
// IsNotFound checks if the given error is the defined errNotFound.
func (cc cacheCluster) IsNotFound(err error) bool { func (cc cacheCluster) IsNotFound(err error) bool {
return err == cc.errNotFound return errors.Is(err, cc.errNotFound)
} }
func (cc cacheCluster) Set(key string, v interface{}) error { // Set sets the cache with key and v, using c.expiry.
func (cc cacheCluster) Set(key string, val interface{}) error {
return cc.SetCtx(context.Background(), key, val)
}
// SetCtx sets the cache with key and v, using c.expiry.
func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{}) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).Set(key, v) return c.(Cache).SetCtx(ctx, key, val)
} }
func (cc cacheCluster) SetWithExpire(key string, v interface{}, expire time.Duration) error { // SetWithExpire sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpire(key string, val interface{}, expire time.Duration) error {
return cc.SetWithExpireCtx(context.Background(), key, val, expire)
}
// SetWithExpireCtx sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).SetWithExpire(key, v, expire) return c.(Cache).SetWithExpireCtx(ctx, key, val, expire)
} }
func (cc cacheCluster) Take(v interface{}, key string, query func(v interface{}) error) error { // Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) Take(val interface{}, key string, query func(val interface{}) error) error {
return cc.TakeCtx(context.Background(), val, key, query)
}
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).Take(v, key, query) return c.(Cache).TakeCtx(ctx, val, key, query)
} }
func (cc cacheCluster) TakeWithExpire(v interface{}, key string, // TakeWithExpire takes the result from cache first, if not found,
query func(v interface{}, expire time.Duration) error) error { // query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return cc.TakeWithExpireCtx(context.Background(), val, key, query)
}
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
} }
return c.(Cache).TakeWithExpire(v, key, query) return c.(Cache).TakeWithExpireCtx(ctx, val, key, query)
} }

View File

@@ -1,7 +1,9 @@
package cache package cache
import ( import (
"context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math" "math"
"strconv" "strconv"
@@ -16,12 +18,18 @@ import (
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
var _ Cache = (*mockedNode)(nil)
type mockedNode struct { type mockedNode struct {
vals map[string][]byte vals map[string][]byte
errNotFound error errNotFound error
} }
func (mc *mockedNode) Del(keys ...string) error { func (mc *mockedNode) Del(keys ...string) error {
return mc.DelCtx(context.Background(), keys...)
}
func (mc *mockedNode) DelCtx(_ context.Context, keys ...string) error {
var be errorx.BatchError var be errorx.BatchError
for _, key := range keys { for _, key := range keys {
@@ -35,21 +43,29 @@ func (mc *mockedNode) Del(keys ...string) error {
return be.Err() return be.Err()
} }
func (mc *mockedNode) Get(key string, v interface{}) error { func (mc *mockedNode) Get(key string, val interface{}) error {
return mc.GetCtx(context.Background(), key, val)
}
func (mc *mockedNode) GetCtx(ctx context.Context, key string, val interface{}) error {
bs, ok := mc.vals[key] bs, ok := mc.vals[key]
if ok { if ok {
return json.Unmarshal(bs, v) return json.Unmarshal(bs, val)
} }
return mc.errNotFound return mc.errNotFound
} }
func (mc *mockedNode) IsNotFound(err error) bool { func (mc *mockedNode) IsNotFound(err error) bool {
return err == mc.errNotFound return errors.Is(err, mc.errNotFound)
} }
func (mc *mockedNode) Set(key string, v interface{}) error { func (mc *mockedNode) Set(key string, val interface{}) error {
data, err := json.Marshal(v) return mc.SetCtx(context.Background(), key, val)
}
func (mc *mockedNode) SetCtx(ctx context.Context, key string, val interface{}) error {
data, err := json.Marshal(val)
if err != nil { if err != nil {
return err return err
} }
@@ -58,25 +74,37 @@ func (mc *mockedNode) Set(key string, v interface{}) error {
return nil return nil
} }
func (mc *mockedNode) SetWithExpire(key string, v interface{}, expire time.Duration) error { func (mc *mockedNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
return mc.Set(key, v) return mc.SetWithExpireCtx(context.Background(), key, val, expire)
} }
func (mc *mockedNode) Take(v interface{}, key string, query func(v interface{}) error) error { func (mc *mockedNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
return mc.Set(key, val)
}
func (mc *mockedNode) Take(val interface{}, key string, query func(val interface{}) error) error {
return mc.TakeCtx(context.Background(), val, key, query)
}
func (mc *mockedNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
if _, ok := mc.vals[key]; ok { if _, ok := mc.vals[key]; ok {
return mc.Get(key, v) return mc.GetCtx(ctx, key, val)
} }
if err := query(v); err != nil { if err := query(val); err != nil {
return err return err
} }
return mc.Set(key, v) return mc.SetCtx(ctx, key, val)
} }
func (mc *mockedNode) TakeWithExpire(v interface{}, key string, query func(v interface{}, expire time.Duration) error) error { func (mc *mockedNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return mc.Take(v, key, func(v interface{}) error { return mc.TakeWithExpireCtx(context.Background(), val, key, query)
return query(v, 0) }
func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
return mc.Take(val, key, func(val interface{}) error {
return query(val, 0)
}) })
} }
@@ -113,18 +141,18 @@ func TestCache_SetDel(t *testing.T) {
} }
} }
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
var v int var val int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v)) assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
assert.Equal(t, i, v) assert.Equal(t, i, val)
} }
assert.Nil(t, c.Del()) assert.Nil(t, c.Del())
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i))) assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
} }
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
var v int var val int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v))) assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
assert.Equal(t, 0, v) assert.Equal(t, 0, val)
} }
} }
@@ -151,18 +179,18 @@ func TestCache_OneNode(t *testing.T) {
} }
} }
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
var v int var val int
assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &v)) assert.Nil(t, c.Get(fmt.Sprintf("key/%d", i), &val))
assert.Equal(t, i, v) assert.Equal(t, i, val)
} }
assert.Nil(t, c.Del()) assert.Nil(t, c.Del())
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i))) assert.Nil(t, c.Del(fmt.Sprintf("key/%d", i)))
} }
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
var v int var val int
assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &v))) assert.True(t, c.IsNotFound(c.Get(fmt.Sprintf("key/%d", i), &val)))
assert.Equal(t, 0, v) assert.Equal(t, 0, val)
} }
} }
@@ -202,9 +230,9 @@ func TestCache_Balance(t *testing.T) {
assert.True(t, entropy > .95, fmt.Sprintf("entropy should be greater than 0.95, but got %.2f", entropy)) assert.True(t, entropy > .95, fmt.Sprintf("entropy should be greater than 0.95, but got %.2f", entropy))
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
var v int var val int
assert.Nil(t, c.Get(strconv.Itoa(i), &v)) assert.Nil(t, c.Get(strconv.Itoa(i), &val))
assert.Equal(t, i, v) assert.Equal(t, i, val)
} }
for i := 0; i < total/10; i++ { for i := 0; i < total/10; i++ {
@@ -216,14 +244,14 @@ func TestCache_Balance(t *testing.T) {
for i := 0; i < total/10; i++ { for i := 0; i < total/10; i++ {
var val int var val int
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(v interface{}) error { assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(val interface{}) error {
*v.(*int) = i *val.(*int) = i
count++ count++
return nil return nil
})) }))
} else { } else {
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(v interface{}, expire time.Duration) error { assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(val interface{}, expire time.Duration) error {
*v.(*int) = i *val.(*int) = i
count++ count++
return nil return nil
})) }))
@@ -244,10 +272,10 @@ func TestCacheNoNode(t *testing.T) {
assert.NotNil(t, c.Get("foo", nil)) assert.NotNil(t, c.Get("foo", nil))
assert.NotNil(t, c.Set("foo", nil)) assert.NotNil(t, c.Set("foo", nil))
assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second)) assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second))
assert.NotNil(t, c.Take(nil, "foo", func(v interface{}) error { assert.NotNil(t, c.Take(nil, "foo", func(val interface{}) error {
return nil return nil
})) }))
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(v interface{}, duration time.Duration) error { assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(val interface{}, duration time.Duration) error {
return nil return nil
})) }))
} }
@@ -255,8 +283,8 @@ func TestCacheNoNode(t *testing.T) {
func calcEntropy(m map[int]int, total int) float64 { func calcEntropy(m map[int]int, total int) float64 {
var entropy float64 var entropy float64
for _, v := range m { for _, val := range m {
proba := float64(v) / float64(total) proba := float64(val) / float64(total)
entropy -= proba * math.Log2(proba) entropy -= proba * math.Log2(proba)
} }

View File

@@ -1,6 +1,7 @@
package cache package cache
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"math/rand" "math/rand"
@@ -61,30 +62,39 @@ func NewNode(rds *redis.Redis, barrier syncx.SingleFlight, st *Stat,
// Del deletes cached values with keys. // Del deletes cached values with keys.
func (c cacheNode) Del(keys ...string) error { func (c cacheNode) Del(keys ...string) error {
return c.DelCtx(context.Background(), keys...)
}
// DelCtx deletes cached values with keys.
func (c cacheNode) DelCtx(ctx context.Context, keys ...string) error {
if len(keys) == 0 { if len(keys) == 0 {
return nil return nil
} }
logger := logx.WithContext(ctx)
if len(keys) > 1 && c.rds.Type == redis.ClusterType { if len(keys) > 1 && c.rds.Type == redis.ClusterType {
for _, key := range keys { for _, key := range keys {
if _, err := c.rds.Del(key); err != nil { if _, err := c.rds.DelCtx(ctx, key); err != nil {
logx.Errorf("failed to clear cache with key: %q, error: %v", key, err) logger.Errorf("failed to clear cache with key: %q, error: %v", key, err)
c.asyncRetryDelCache(key) c.asyncRetryDelCache(key)
} }
} }
} else { } else if _, err := c.rds.DelCtx(ctx, keys...); err != nil {
if _, err := c.rds.Del(keys...); err != nil { logger.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err)
logx.Errorf("failed to clear cache with keys: %q, error: %v", formatKeys(keys), err) c.asyncRetryDelCache(keys...)
c.asyncRetryDelCache(keys...)
}
} }
return nil return nil
} }
// Get gets the cache with key and fills into v. // Get gets the cache with key and fills into v.
func (c cacheNode) Get(key string, v interface{}) error { func (c cacheNode) Get(key string, val interface{}) error {
err := c.doGetCache(key, v) return c.GetCtx(context.Background(), key, val)
}
// GetCtx gets the cache with key and fills into v.
func (c cacheNode) GetCtx(ctx context.Context, key string, val interface{}) error {
err := c.doGetCache(ctx, key, val)
if err == errPlaceholder { if err == errPlaceholder {
return c.errNotFound return c.errNotFound
} }
@@ -94,22 +104,32 @@ func (c cacheNode) Get(key string, v interface{}) error {
// IsNotFound checks if the given error is the defined errNotFound. // IsNotFound checks if the given error is the defined errNotFound.
func (c cacheNode) IsNotFound(err error) bool { func (c cacheNode) IsNotFound(err error) bool {
return err == c.errNotFound return errors.Is(err, c.errNotFound)
} }
// Set sets the cache with key and v, using c.expiry. // Set sets the cache with key and v, using c.expiry.
func (c cacheNode) Set(key string, v interface{}) error { func (c cacheNode) Set(key string, val interface{}) error {
return c.SetWithExpire(key, v, c.aroundDuration(c.expiry)) return c.SetCtx(context.Background(), key, val)
}
// SetCtx sets the cache with key and v, using c.expiry.
func (c cacheNode) SetCtx(ctx context.Context, key string, val interface{}) error {
return c.SetWithExpireCtx(ctx, key, val, c.aroundDuration(c.expiry))
} }
// SetWithExpire sets the cache with key and v, using given expire. // SetWithExpire sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpire(key string, v interface{}, expire time.Duration) error { func (c cacheNode) SetWithExpire(key string, val interface{}, expire time.Duration) error {
data, err := jsonx.Marshal(v) return c.SetWithExpireCtx(context.Background(), key, val, expire)
}
// SetWithExpireCtx sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error {
data, err := jsonx.Marshal(val)
if err != nil { if err != nil {
return err return err
} }
return c.rds.Setex(key, string(data), int(expire.Seconds())) return c.rds.SetexCtx(ctx, key, string(data), int(expire.Seconds()))
} }
// String returns a string that represents the cacheNode. // String returns a string that represents the cacheNode.
@@ -119,21 +139,32 @@ func (c cacheNode) String() string {
// Take takes the result from cache first, if not found, // Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) Take(v interface{}, key string, query func(v interface{}) error) error { func (c cacheNode) Take(val interface{}, key string, query func(val interface{}) error) error {
return c.doTake(v, key, query, func(v interface{}) error { return c.TakeCtx(context.Background(), val, key, query)
return c.Set(key, v) }
// TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error {
return c.doTake(ctx, val, key, query, func(v interface{}) error {
return c.SetCtx(ctx, key, v)
}) })
} }
// TakeWithExpire takes the result from cache first, if not found, // TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpire(v interface{}, key string, query func(v interface{}, func (c cacheNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
expire time.Duration) error) error { return c.TakeWithExpireCtx(context.Background(), val, key, query)
}
// TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error {
expire := c.aroundDuration(c.expiry) expire := c.aroundDuration(c.expiry)
return c.doTake(v, key, func(v interface{}) error { return c.doTake(ctx, val, key, func(v interface{}) error {
return query(v, expire) return query(v, expire)
}, func(v interface{}) error { }, func(v interface{}) error {
return c.SetWithExpire(key, v, expire) return c.SetWithExpireCtx(ctx, key, v, expire)
}) })
} }
@@ -148,9 +179,9 @@ func (c cacheNode) asyncRetryDelCache(keys ...string) {
}, keys...) }, keys...)
} }
func (c cacheNode) doGetCache(key string, v interface{}) error { func (c cacheNode) doGetCache(ctx context.Context, key string, v interface{}) error {
c.stat.IncrementTotal() c.stat.IncrementTotal()
data, err := c.rds.Get(key) data, err := c.rds.GetCtx(ctx, key)
if err != nil { if err != nil {
c.stat.IncrementMiss() c.stat.IncrementMiss()
return err return err
@@ -166,13 +197,14 @@ func (c cacheNode) doGetCache(key string, v interface{}) error {
return errPlaceholder return errPlaceholder
} }
return c.processCache(key, data, v) return c.processCache(ctx, key, data, v)
} }
func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) error, func (c cacheNode) doTake(ctx context.Context, v interface{}, key string,
cacheVal func(v interface{}) error) error { query func(v interface{}) error, cacheVal func(v interface{}) error) error {
logger := logx.WithContext(ctx)
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) { val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) {
if err := c.doGetCache(key, v); err != nil { if err := c.doGetCache(ctx, key, v); err != nil {
if err == errPlaceholder { if err == errPlaceholder {
return nil, c.errNotFound return nil, c.errNotFound
} else if err != c.errNotFound { } else if err != c.errNotFound {
@@ -183,8 +215,8 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
} }
if err = query(v); err == c.errNotFound { if err = query(v); err == c.errNotFound {
if err = c.setCacheWithNotFound(key); err != nil { if err = c.setCacheWithNotFound(ctx, key); err != nil {
logx.Error(err) logger.Error(err)
} }
return nil, c.errNotFound return nil, c.errNotFound
@@ -194,7 +226,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
} }
if err = cacheVal(v); err != nil { if err = cacheVal(v); err != nil {
logx.Error(err) logger.Error(err)
} }
} }
@@ -214,7 +246,7 @@ func (c cacheNode) doTake(v interface{}, key string, query func(v interface{}) e
return jsonx.Unmarshal(val.([]byte), v) return jsonx.Unmarshal(val.([]byte), v)
} }
func (c cacheNode) processCache(key, data string, v interface{}) error { func (c cacheNode) processCache(ctx context.Context, key, data string, v interface{}) error {
err := jsonx.Unmarshal([]byte(data), v) err := jsonx.Unmarshal([]byte(data), v)
if err == nil { if err == nil {
return nil return nil
@@ -222,10 +254,11 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
report := fmt.Sprintf("unmarshal cache, node: %s, key: %s, value: %s, error: %v", report := fmt.Sprintf("unmarshal cache, node: %s, key: %s, value: %s, error: %v",
c.rds.Addr, key, data, err) c.rds.Addr, key, data, err)
logx.Error(report) logger := logx.WithContext(ctx)
logger.Error(report)
stat.Report(report) stat.Report(report)
if _, e := c.rds.Del(key); e != nil { if _, e := c.rds.DelCtx(ctx, key); e != nil {
logx.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v", logger.Errorf("delete invalid cache, node: %s, key: %s, value: %s, error: %v",
c.rds.Addr, key, data, e) c.rds.Addr, key, data, e)
} }
@@ -233,6 +266,6 @@ func (c cacheNode) processCache(key, data string, v interface{}) error {
return c.errNotFound return c.errNotFound
} }
func (c cacheNode) setCacheWithNotFound(key string) error { func (c cacheNode) setCacheWithNotFound(ctx context.Context, key string) error {
return c.rds.Setex(key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds())) return c.rds.SetexCtx(ctx, key, notFoundPlaceholder, int(c.aroundDuration(c.notFoundExpiry).Seconds()))
} }

83
core/stores/redis/hook.go Normal file
View File

@@ -0,0 +1,83 @@
package redis
import (
"context"
"strings"
"time"
red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/timex"
)
var (
startTimeKey = contextKey("startTime")
durationHook = hook{}
)
type (
contextKey string
hook struct{}
)
func (h hook) BeforeProcess(ctx context.Context, _ red.Cmder) (context.Context, error) {
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
}
func (h hook) AfterProcess(ctx context.Context, cmd red.Cmder) error {
val := ctx.Value(startTimeKey)
if val == nil {
return nil
}
start, ok := val.(time.Duration)
if !ok {
return nil
}
duration := timex.Since(start)
if duration > slowThreshold.Load() {
logDuration(ctx, cmd, duration)
}
return nil
}
func (h hook) BeforeProcessPipeline(ctx context.Context, _ []red.Cmder) (context.Context, error) {
return context.WithValue(ctx, startTimeKey, timex.Now()), nil
}
func (h hook) AfterProcessPipeline(ctx context.Context, cmds []red.Cmder) error {
if len(cmds) == 0 {
return nil
}
val := ctx.Value(startTimeKey)
if val == nil {
return nil
}
start, ok := val.(time.Duration)
if !ok {
return nil
}
duration := timex.Since(start)
if duration > slowThreshold.Load()*time.Duration(len(cmds)) {
logDuration(ctx, cmds[0], duration)
}
return nil
}
func logDuration(ctx context.Context, cmd red.Cmder, duration time.Duration) {
var buf strings.Builder
for i, arg := range cmd.Args() {
if i > 0 {
buf.WriteByte(' ')
}
buf.WriteString(mapping.Repr(arg))
}
logx.WithContext(ctx).WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
}

View File

@@ -0,0 +1,137 @@
package redis
import (
"context"
"log"
"strings"
"testing"
"time"
red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
)
func TestHookProcessCase1(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
assert.False(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessCase2(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcess(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
time.Sleep(slowThreshold.Load() + time.Millisecond)
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background(), "foo", "bar")))
assert.True(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessCase3(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
assert.Nil(t, durationHook.AfterProcess(context.Background(), red.NewCmd(context.Background())))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessCase4(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcess(ctx, red.NewCmd(context.Background())))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase1(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.False(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessPipelineCase2(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx, err := durationHook.BeforeProcessPipeline(context.Background(), nil)
if err != nil {
t.Fatal(err)
}
time.Sleep(slowThreshold.Load() + time.Millisecond)
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background(), "foo", "bar"),
}))
assert.True(t, strings.Contains(buf.String(), "slow"))
}
func TestHookProcessPipelineCase3(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
assert.Nil(t, durationHook.AfterProcessPipeline(context.Background(), []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase4(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, []red.Cmder{
red.NewCmd(context.Background()),
}))
assert.True(t, buf.Len() == 0)
}
func TestHookProcessPipelineCase5(t *testing.T) {
writer := log.Writer()
var buf strings.Builder
log.SetOutput(&buf)
defer log.SetOutput(writer)
ctx := context.WithValue(context.Background(), startTimeKey, "foo")
assert.Nil(t, durationHook.AfterProcessPipeline(ctx, nil))
assert.True(t, buf.Len() == 0)
}

View File

@@ -1,32 +0,0 @@
package redis
import (
"strings"
red "github.com/go-redis/redis"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/mapping"
"github.com/zeromicro/go-zero/core/timex"
)
func checkDuration(proc func(red.Cmder) error) func(red.Cmder) error {
return func(cmd red.Cmder) error {
start := timex.Now()
defer func() {
duration := timex.Since(start)
if duration > slowThreshold.Load() {
var buf strings.Builder
for i, arg := range cmd.Args() {
if i > 0 {
buf.WriteByte(' ')
}
buf.WriteString(mapping.Repr(arg))
}
logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
}
}()
return proc(cmd)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
package redis package redis
import ( import (
"context"
"crypto/tls" "crypto/tls"
"errors" "errors"
"io" "io"
@@ -9,8 +10,9 @@ import (
"time" "time"
"github.com/alicebob/miniredis/v2" "github.com/alicebob/miniredis/v2"
red "github.com/go-redis/redis" red "github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
) )
@@ -963,13 +965,14 @@ func TestRedis_SortedSet(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
client.Zadd("second", 2, "aa") client.Zadd("second", 2, "aa")
client.Zadd("third", 3, "bbb") client.Zadd("third", 3, "bbb")
val, err = client.Zunionstore("union", ZStore{ val, err = client.Zunionstore("union", &ZStore{
Keys: []string{"second", "third"},
Weights: []float64{1, 2}, Weights: []float64{1, 2},
Aggregate: "SUM", Aggregate: "SUM",
}, "second", "third") })
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(2), val) assert.Equal(t, int64(2), val)
_, err = New(client.Addr, badType()).Zunionstore("union", ZStore{}) _, err = New(client.Addr, badType()).Zunionstore("union", &ZStore{})
assert.NotNil(t, err) assert.NotNil(t, err)
vals, err = client.Zrange("union", 0, 10000) vals, err = client.Zrange("union", 0, 10000)
assert.Nil(t, err) assert.Nil(t, err)
@@ -987,9 +990,9 @@ func TestRedis_Pipelined(t *testing.T) {
})) }))
err := client.Pipelined( err := client.Pipelined(
func(pipe Pipeliner) error { func(pipe Pipeliner) error {
pipe.Incr("pipelined_counter") pipe.Incr(context.Background(), "pipelined_counter")
pipe.Expire("pipelined_counter", time.Hour) pipe.Expire(context.Background(), "pipelined_counter", time.Hour)
pipe.ZAdd("zadd", Z{Score: 12, Member: "zadd"}) pipe.ZAdd(context.Background(), "zadd", &Z{Score: 12, Member: "zadd"})
return nil return nil
}, },
) )
@@ -1135,6 +1138,8 @@ func TestRedis_WithPass(t *testing.T) {
} }
func runOnRedis(t *testing.T, fn func(client *Redis)) { func runOnRedis(t *testing.T, fn func(client *Redis)) {
logx.Disable()
s, err := miniredis.Run() s, err := miniredis.Run()
assert.Nil(t, err) assert.Nil(t, err)
defer func() { defer func() {
@@ -1153,6 +1158,8 @@ func runOnRedis(t *testing.T, fn func(client *Redis)) {
} }
func runOnRedisTLS(t *testing.T, fn func(client *Redis)) { func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
logx.Disable()
s, err := miniredis.RunTLS(&tls.Config{ s, err := miniredis.RunTLS(&tls.Config{
Certificates: make([]tls.Certificate, 1), Certificates: make([]tls.Certificate, 1),
InsecureSkipVerify: true, InsecureSkipVerify: true,
@@ -1182,6 +1189,6 @@ type mockedNode struct {
RedisNode RedisNode
} }
func (n mockedNode) BLPop(timeout time.Duration, keys ...string) *red.StringSliceCmd { func (n mockedNode) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *red.StringSliceCmd {
return red.NewStringSliceCmd("foo", "bar") return red.NewStringSliceCmd(context.Background(), "foo", "bar")
} }

View File

@@ -3,7 +3,7 @@ package redis
import ( import (
"fmt" "fmt"
red "github.com/go-redis/redis" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )

View File

@@ -4,7 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"io" "io"
red "github.com/go-redis/redis" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
@@ -32,7 +32,8 @@ func getClient(r *Redis) (*red.Client, error) {
MinIdleConns: idleConns, MinIdleConns: idleConns,
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
}) })
store.WrapProcess(checkDuration) store.AddHook(durationHook)
return store, nil return store, nil
}) })
if err != nil { if err != nil {

View File

@@ -4,7 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"io" "io"
red "github.com/go-redis/redis" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
@@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
MinIdleConns: idleConns, MinIdleConns: idleConns,
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
}) })
store.WrapProcess(checkDuration) store.AddHook(durationHook)
return store, nil return store, nil
}) })

View File

@@ -5,7 +5,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
red "github.com/go-redis/redis" red "github.com/go-redis/redis/v8"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
) )

View File

@@ -17,10 +17,12 @@ func CreateRedis() (r *redis.Redis, clean func(), err error) {
return redis.New(mr.Addr()), func() { return redis.New(mr.Addr()), func() {
ch := make(chan lang.PlaceholderType) ch := make(chan lang.PlaceholderType)
go func() { go func() {
mr.Close() mr.Close()
close(ch) close(ch)
}() }()
select { select {
case <-ch: case <-ch:
case <-time.After(time.Second): case <-time.After(time.Second):

View File

@@ -4,9 +4,12 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
) )
func TestScriptCache(t *testing.T) { func TestScriptCache(t *testing.T) {
logx.Disable()
cache := GetScriptCache() cache := GetScriptCache()
cache.SetSha("foo", "bar") cache.SetSha("foo", "bar")
cache.SetSha("bla", "blabla") cache.SetSha("bla", "blabla")

View File

@@ -7,6 +7,9 @@ import (
"github.com/zeromicro/go-zero/core/lang" "github.com/zeromicro/go-zero/core/lang"
) )
// errTimeout indicates a timeout.
var errTimeout = errors.New("timeout")
type ( type (
// Ticker interface wraps the Chan and Stop methods. // Ticker interface wraps the Chan and Stop methods.
Ticker interface { Ticker interface {
@@ -70,7 +73,7 @@ func (ft *fakeTicker) Tick() {
func (ft *fakeTicker) Wait(d time.Duration) error { func (ft *fakeTicker) Wait(d time.Duration) error {
select { select {
case <-time.After(d): case <-time.After(d):
return errors.New("timeout") return errTimeout
case <-ft.done: case <-ft.done:
return nil return nil
} }

10
go.mod
View File

@@ -7,7 +7,6 @@ require (
github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.17.0 github.com/alicebob/miniredis/v2 v2.17.0
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0 github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
@@ -28,7 +27,7 @@ require (
go.uber.org/automaxprocs v1.4.0 go.uber.org/automaxprocs v1.4.0
go.uber.org/goleak v1.1.12 go.uber.org/goleak v1.1.12
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
google.golang.org/grpc v1.43.0 google.golang.org/grpc v1.44.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/cheggaaa/pb.v1 v1.0.28
gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/h2non/gock.v1 v1.1.2
@@ -42,10 +41,11 @@ require (
require ( require (
github.com/fatih/color v1.10.0 // indirect github.com/fatih/color v1.10.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-redis/redis/v8 v8.11.4
github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/openzipkin/zipkin-go v0.4.0 // indirect github.com/openzipkin/zipkin-go v0.4.0 // indirect
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2 // indirect google.golang.org/genproto v0.0.0-20220211171837-173942840c17 // indirect
k8s.io/klog/v2 v2.40.1 // indirect k8s.io/klog/v2 v2.40.1 // indirect
) )

37
go.sum
View File

@@ -37,7 +37,6 @@ github.com/ClickHouse/clickhouse-go v1.5.1/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHg
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
@@ -60,10 +59,9 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk= github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
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.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/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/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/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -73,7 +71,6 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
@@ -87,6 +84,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
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/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@@ -100,7 +99,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -142,8 +140,8 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -352,7 +350,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -486,8 +483,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -548,10 +545,12 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -647,8 +646,8 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2 h1:z+R4M/SuyaRsj1zu3WC+nIQyfSrSIpuDcY01/R3uCtg= google.golang.org/genproto v0.0.0-20220211171837-173942840c17 h1:2X+CNIheCutWRyKRte8szGxrE5ggtV4U+NKAbh/oLhg=
google.golang.org/genproto v0.0.0-20220112215332-a9c7c0acf9f2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -660,10 +659,9 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 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-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 v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -719,7 +717,6 @@ k8s.io/client-go v0.20.12 h1:U75SxTC31BHT9i7CbX/hL4v+U1Wkzy/E1vt5ClDPp3I=
k8s.io/client-go v0.20.12/go.mod h1:NBJj6Evp73Xy/4v/O/RDRaH0+3JoxNfjRxkyRgrdbsA= k8s.io/client-go v0.20.12/go.mod h1:NBJj6Evp73Xy/4v/O/RDRaH0+3JoxNfjRxkyRgrdbsA=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4=
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=

View File

@@ -11,6 +11,8 @@
[![Release](https://img.shields.io/github/v/release/zeromicro/go-zero.svg?style=flat-square)](https://github.com/zeromicro/go-zero) [![Release](https://img.shields.io/github/v/release/zeromicro/go-zero.svg?style=flat-square)](https://github.com/zeromicro/go-zero)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
> ***缩短从需求到上线的距离***
**注意为了满足开源基金会要求go-zero 从好未来tal-tech组织下迁移至中立的 GitHub 组织zeromicro** **注意为了满足开源基金会要求go-zero 从好未来tal-tech组织下迁移至中立的 GitHub 组织zeromicro**
## 0. go-zero 介绍 ## 0. go-zero 介绍
@@ -87,7 +89,7 @@ go-zero 是一个集成了各种工程实践的包含 web 和 rpc 框架,有
在项目目录下通过如下命令安装: 在项目目录下通过如下命令安装:
```shell ```shell
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero
``` ```
## 5. Quick Start ## 5. Quick Start
@@ -104,10 +106,10 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
```shell ```shell
# Go 1.15 及之前版本 # Go 1.15 及之前版本
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl@latest GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# Go 1.16 及以后版本 # Go 1.16 及以后版本
GOPROXY=https://goproxy.cn/,direct go install github.com/tal-tech/go-zero/tools/goctl@latest GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest
``` ```
确保 goctl 可执行 确保 goctl 可执行
@@ -232,12 +234,14 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>46. 上海游族网络 >46. 上海游族网络
>47. 深信服 >47. 深信服
>48. 中免日上科技互联有限公司 >48. 中免日上科技互联有限公司
>48. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED >49. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
>48. 馨科智(深圳)科技有限公司 >50. 馨科智(深圳)科技有限公司
>48. 成都松珀科技有限公司 >51. 成都松珀科技有限公司
>48. 亿景智联 >52. 亿景智联
>48. 上海扩博智能技术有限公司 >53. 上海扩博智能技术有限公司
>48. 一犀科技成都有限公司 >54. 一犀科技成都有限公司
>55. 北京术杰科技有限公司
>56. 时代脉搏网络科技(云浮市)有限公司
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。 如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -90,7 +90,7 @@ As below, go-zero protects the system with a couple of layers and mechanisms:
Run the following command under your project: Run the following command under your project:
```shell ```shell
go get -u github.com/tal-tech/go-zero go get -u github.com/zeromicro/go-zero
``` ```
## 6. Quick Start ## 6. Quick Start
@@ -107,10 +107,10 @@ go get -u github.com/tal-tech/go-zero
```shell ```shell
# for Go 1.15 and earlier # for Go 1.15 and earlier
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl@latest GO111MODULE=on go get -u github.com/zeromicro/go-zero/tools/goctl@latest
# for Go 1.16 and later # for Go 1.16 and later
go install github.com/tal-tech/go-zero/tools/goctl@latest go install github.com/zeromicro/go-zero/tools/goctl@latest
``` ```
make sure goctl is executable. make sure goctl is executable.

View File

@@ -8,15 +8,15 @@ import (
"text/template" "text/template"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const apiTemplate = ` const apiTemplate = `
syntax = "v1" syntax = "v1"
info( info (
title: // TODO: add title title: // TODO: add title
desc: // TODO: add description desc: // TODO: add description
author: "{{.gitUser}}" author: "{{.gitUser}}"

View File

@@ -3,8 +3,8 @@ package apigen
import ( import (
"fmt" "fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -4,9 +4,9 @@ import (
"errors" "errors"
"strings" "strings"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
) )
// DartCommand create dart network request code // DartCommand create dart network request code

View File

@@ -4,7 +4,7 @@ import (
"os" "os"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
) )
const apiTemplate = `import 'api.dart'; const apiTemplate = `import 'api.dart';

View File

@@ -4,7 +4,7 @@ import (
"os" "os"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
) )
const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}-- const dataTemplate = `// --{{with .Info}}{{.Title}}{{end}}--

View File

@@ -6,8 +6,8 @@ import (
"os" "os"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/zeromicro/go-zero/tools/goctl/api/util"
) )
func lowCamelCase(s string) string { func lowCamelCase(s string) string {

View File

@@ -7,10 +7,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/tal-tech/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen" "github.com/zeromicro/go-zero/tools/goctl/api/gogen"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/zeromicro/go-zero/tools/goctl/api/util"
) )
const ( const (

View File

@@ -7,9 +7,9 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// DocCommand generate markdown doc file // DocCommand generate markdown doc file

View File

@@ -11,11 +11,11 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tal-tech/go-zero/core/errorx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -39,5 +39,5 @@ service A-api {
func TestFormat(t *testing.T) { func TestFormat(t *testing.T) {
r, err := apiFormat(notFormattedStr) r, err := apiFormat(notFormattedStr)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, r, formattedStr) assert.Equal(t, formattedStr, r)
} }

View File

@@ -12,14 +12,14 @@ import (
"time" "time"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
apiformat "github.com/tal-tech/go-zero/tools/goctl/api/format"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const tmpFile = "%s-%d" const tmpFile = "%s-%d"

View File

@@ -9,7 +9,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser" "github.com/zeromicro/go-zero/tools/goctl/api/parser"
) )
const testApiTemplate = ` const testApiTemplate = `

View File

@@ -4,10 +4,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const ( const (

View File

@@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
) )
const ( const (

View File

@@ -5,13 +5,13 @@ import (
"path" "path"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/internal/version"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const ( const (

View File

@@ -6,12 +6,12 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const logicTemplate = `package {{.pkgName}} const logicTemplate = `package {{.pkgName}}

View File

@@ -4,11 +4,11 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const mainTemplate = `package main const mainTemplate = `package main

View File

@@ -3,9 +3,9 @@ package gogen
import ( import (
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
) )
var middlewareImplementCode = ` var middlewareImplementCode = `

View File

@@ -8,12 +8,12 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/core/collection" "github.com/zeromicro/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const ( const (

View File

@@ -4,11 +4,11 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars" "github.com/zeromicro/go-zero/tools/goctl/vars"
) )
const ( const (

View File

@@ -7,11 +7,11 @@ import (
"path" "path"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config" "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/format"
) )
const ( const (

View File

@@ -3,8 +3,8 @@ package gogen
import ( import (
"fmt" "fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
func TestGenTemplates(t *testing.T) { func TestGenTemplates(t *testing.T) {

View File

@@ -9,11 +9,11 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/core/collection" "github.com/zeromicro/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/ctx" "github.com/zeromicro/go-zero/tools/goctl/util/ctx"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
type fileGenConfig struct { type fileGenConfig struct {

View File

@@ -6,10 +6,10 @@ import (
"strings" "strings"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// JavaCommand the generate java code command entrance // JavaCommand the generate java code command entrance

View File

@@ -10,11 +10,11 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -6,10 +6,10 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
) )
const packetTemplate = `package com.xhb.logic.http.packet.{{.packet}}; const packetTemplate = `package com.xhb.logic.http.packet.{{.packet}};

View File

@@ -6,9 +6,9 @@ import (
"io" "io"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
func writeProperty(writer io.Writer, member spec.Member, indent int) error { func writeProperty(writer io.Writer, member spec.Member, indent int) error {

View File

@@ -3,8 +3,8 @@ package ktgen
import ( import (
"errors" "errors"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
) )
// KtCommand the generate kotlin code command entrance // KtCommand the generate kotlin code command entrance

View File

@@ -7,7 +7,7 @@ import (
"text/template" "text/template"
"github.com/iancoleman/strcase" "github.com/iancoleman/strcase"
"github.com/tal-tech/go-zero/tools/goctl/api/util" "github.com/zeromicro/go-zero/tools/goctl/api/util"
) )
var funcsMap = template.FuncMap{ var funcsMap = template.FuncMap{

View File

@@ -7,7 +7,7 @@ import (
"text/template" "text/template"
"github.com/iancoleman/strcase" "github.com/iancoleman/strcase"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
) )
const ( const (

View File

@@ -7,11 +7,11 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
conf "github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const apiTemplate = ` const apiTemplate = `

View File

@@ -3,8 +3,8 @@ package new
import ( import (
"fmt" "fmt"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -5,7 +5,7 @@ import (
"path" "path"
"sort" "sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
const prefixKey = "prefix" const prefixKey = "prefix"

View File

@@ -7,9 +7,9 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/util/console"
"github.com/zeromicro/antlr" "github.com/zeromicro/antlr"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
) )
type ( type (

View File

@@ -5,9 +5,9 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/util/console"
"github.com/zeromicro/antlr" "github.com/zeromicro/antlr"
"github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
) )
type ( type (

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
// ImportExpr defines import syntax for api // ImportExpr defines import syntax for api

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
// InfoExpr defines info syntax for api // InfoExpr defines info syntax for api

View File

@@ -3,7 +3,7 @@ package ast
import ( import (
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
// KvExpr describes key-value for api // KvExpr describes key-value for api

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
// Service describes service for api syntax // Service describes service for api syntax

View File

@@ -1,7 +1,7 @@
package ast package ast
import ( import (
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
// SyntaxExpr describes syntax for api // SyntaxExpr describes syntax for api

View File

@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
type ( type (

View File

@@ -634,4 +634,3 @@ func NewSyntaxLitContext(parser antlr.Parser, parent antlr.ParserRuleContext, in
return p return p
} }

View File

@@ -8,8 +8,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
var ( var (

View File

@@ -5,8 +5,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
var parser = ast.NewParser(ast.WithParserPrefix("test.api"), ast.WithParserDebug()) var parser = ast.NewParser(ast.WithParserPrefix("test.api"), ast.WithParserDebug())

View File

@@ -5,8 +5,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
var importAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} { var importAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
var infoAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} { var infoAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
func TestBody(t *testing.T) { func TestBody(t *testing.T) {

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
var syntaxAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} { var syntaxAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
) )
var fieldAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} { var fieldAccept = func(p *api.ApiParserParser, visitor *ast.ApiVisitor) interface{} {

View File

@@ -5,9 +5,9 @@ import (
"path/filepath" "path/filepath"
"unicode" "unicode"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/ast" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/ast"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
) )
type parser struct { type parser struct {

View File

@@ -4,7 +4,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
) )
var testApi = "// syntax doc\nsyntax = \"v1\" // syntax comment\n\n// type doc\ntype Request {\n\tName string `path:\"name,options=you|me\"`\n}\n\ntype Response {\n\tMessage string `json:\"message\"`\n}\n\n// service doc\nservice greet-api {\n\t// handler doc\n\t@handler GreetHandler // handler comment\n\tget /from/:name(Request) returns (Response);\n}" var testApi = "// syntax doc\nsyntax = \"v1\" // syntax comment\n\n// type doc\ntype Request {\n\tName string `path:\"name,options=you|me\"`\n}\n\ntype Response {\n\tMessage string `json:\"message\"`\n}\n\n// service doc\nservice greet-api {\n\t// handler doc\n\t@handler GreetHandler // handler comment\n\tget /from/:name(Request) returns (Response);\n}"

View File

@@ -5,8 +5,8 @@ import (
"path" "path"
"strings" "strings"
"github.com/tal-tech/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
) )
const ( const (

View File

@@ -5,10 +5,10 @@ import (
"fmt" "fmt"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// TsCommand provides the entry to generate typescript codes // TsCommand provides the entry to generate typescript codes

View File

@@ -5,9 +5,9 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -6,10 +6,10 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
const ( const (

View File

@@ -6,9 +6,9 @@ import (
"io" "io"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util" apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
) )
func writeProperty(writer io.Writer, member spec.Member, indent int) error { func writeProperty(writer io.Writer, member spec.Member, indent int) error {

View File

@@ -8,9 +8,9 @@ import (
"path" "path"
"strings" "strings"
"github.com/tal-tech/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// MaybeCreateFile creates file if not exists // MaybeCreateFile creates file if not exists

View File

@@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/api/parser"
) )
// GoValidateApi verifies whether the api has a syntax error // GoValidateApi verifies whether the api has a syntax error

View File

@@ -6,8 +6,8 @@ import (
"os/exec" "os/exec"
"runtime" "runtime"
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
) )
const ( const (

View File

@@ -6,7 +6,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/internal/version"
) )
type env map[string]string type env map[string]string

View File

@@ -0,0 +1,79 @@
package completion
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"github.com/logrusorgru/aurora"
"github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
"github.com/zeromicro/go-zero/tools/goctl/vars"
)
func Completion(c *cli.Context) error {
goos := runtime.GOOS
if goos == vars.OsWindows {
return fmt.Errorf("%q: only support unix-like OS", goos)
}
name := c.String("name")
if len(name) == 0 {
name = defaultCompletionFilename
}
if filepath.IsAbs(name) {
return fmt.Errorf("unsupport absolute path: %q", name)
}
home, err := pathx.GetAutoCompleteHome()
if err != nil {
return err
}
buffer := bytes.NewBuffer(nil)
zshF := filepath.Join(home, "zsh", defaultCompletionFilename)
err = pathx.MkdirIfNotExist(filepath.Dir(zshF))
if err != nil {
return err
}
bashF := filepath.Join(home, "bash", defaultCompletionFilename)
err = pathx.MkdirIfNotExist(filepath.Dir(bashF))
if err != nil {
return err
}
flag := magic
err = ioutil.WriteFile(zshF, zsh, os.ModePerm)
if err != nil {
return err
}
flag |= flagZsh
err = ioutil.WriteFile(bashF, bash, os.ModePerm)
if err != nil {
return err
}
flag |= flagBash
buffer.WriteString(aurora.BrightGreen("generation auto completion success!\n").String())
buffer.WriteString(aurora.BrightGreen("executes the following script to setting shell:\n").String())
switch flag {
case magic | flagZsh:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc", zshF)).String())
case magic | flagBash:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc", bashF)).String())
case magic | flagZsh | flagBash:
buffer.WriteString(aurora.BrightCyan(fmt.Sprintf(`echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc
or
echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc`, zshF, bashF)).String())
default:
return nil
}
fmt.Println(buffer.String())
return nil
}

View File

@@ -0,0 +1,9 @@
package completion
const BashCompletionFlag = `generate-goctl-completion`
const defaultCompletionFilename = "goctl_autocomplete"
const (
magic = 1 << iota
flagZsh
flagBash
)

View File

@@ -0,0 +1,51 @@
package completion
import "fmt"
var zsh = []byte(fmt.Sprintf(`#compdef $PROG
_cli_zsh_autocomplete() {
local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --%s)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --%s)}")
fi
if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi
return
}
compdef _cli_zsh_autocomplete $PROG
`, BashCompletionFlag, BashCompletionFlag))
var bash = []byte(fmt.Sprintf(`#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --%s )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --%s )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
unset PROG
`, BashCompletionFlag, BashCompletionFlag))

Some files were not shown because too many files have changed in this diff Show More