rename sharedcalls to singleflight (#1017)

master
Kevin Wan 3 years ago committed by GitHub
parent f070d447ef
commit 5cc9eb0de4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -34,7 +34,7 @@ type (
expire time.Duration expire time.Duration
timingWheel *TimingWheel timingWheel *TimingWheel
lruCache lru lruCache lru
barrier syncx.SharedCalls barrier syncx.SingleFlight
unstableExpiry mathx.Unstable unstableExpiry mathx.Unstable
stats *cacheStat stats *cacheStat
} }
@ -46,7 +46,7 @@ func NewCache(expire time.Duration, opts ...CacheOption) (*Cache, error) {
data: make(map[string]interface{}), data: make(map[string]interface{}),
expire: expire, expire: expire,
lruCache: emptyLruCache, lruCache: emptyLruCache,
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
} }

@ -29,7 +29,7 @@ type (
) )
// New returns a Cache. // New returns a Cache.
func New(c ClusterConf, barrier syncx.SharedCalls, st *Stat, errNotFound error, func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
opts ...Option) Cache { opts ...Option) Cache {
if len(c) == 0 || TotalWeights(c) <= 0 { if len(c) == 0 || TotalWeights(c) <= 0 {
log.Fatal("no cache nodes") log.Fatal("no cache nodes")

@ -104,7 +104,7 @@ func TestCache_SetDel(t *testing.T) {
Weight: 100, Weight: 100,
}, },
} }
c := New(conf, syncx.NewSharedCalls(), NewStat("mock"), errPlaceholder) c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i)) assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i))
@ -142,7 +142,7 @@ func TestCache_OneNode(t *testing.T) {
Weight: 100, Weight: 100,
}, },
} }
c := New(conf, syncx.NewSharedCalls(), NewStat("mock"), errPlaceholder) c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i)) assert.Nil(t, c.Set(fmt.Sprintf("key/%d", i), i))

@ -29,7 +29,7 @@ type cacheNode struct {
rds *redis.Redis rds *redis.Redis
expiry time.Duration expiry time.Duration
notFoundExpiry time.Duration notFoundExpiry time.Duration
barrier syncx.SharedCalls barrier syncx.SingleFlight
r *rand.Rand r *rand.Rand
lock *sync.Mutex lock *sync.Mutex
unstableExpiry mathx.Unstable unstableExpiry mathx.Unstable
@ -43,7 +43,7 @@ type cacheNode struct {
// st is used to stat the cache. // st is used to stat the cache.
// errNotFound defines the error that returned on cache not found. // errNotFound defines the error that returned on cache not found.
// opts are the options that customize the cacheNode. // opts are the options that customize the cacheNode.
func NewNode(rds *redis.Redis, barrier syncx.SharedCalls, st *Stat, func NewNode(rds *redis.Redis, barrier syncx.SingleFlight, st *Stat,
errNotFound error, opts ...Option) Cache { errNotFound error, opts ...Option) Cache {
o := newOptions(opts...) o := newOptions(opts...)
return cacheNode{ return cacheNode{

@ -96,7 +96,7 @@ func TestCacheNode_Take(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@ -123,7 +123,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@ -162,7 +162,7 @@ func TestCacheNode_TakeWithExpire(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@ -189,7 +189,7 @@ func TestCacheNode_String(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),
@ -206,7 +206,7 @@ func TestCacheValueWithBigInt(t *testing.T) {
cn := cacheNode{ cn := cacheNode{
rds: store, rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())), r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSharedCalls(), barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex), lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation), unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"), stat: NewStat("any"),

@ -11,8 +11,8 @@ var (
// ErrNotFound is an alias of mgo.ErrNotFound. // ErrNotFound is an alias of mgo.ErrNotFound.
ErrNotFound = mgo.ErrNotFound ErrNotFound = mgo.ErrNotFound
// can't use one SharedCalls per conn, because multiple conns may share the same cache key. // can't use one SingleFlight per conn, because multiple conns may share the same cache key.
sharedCalls = syncx.NewSharedCalls() sharedCalls = syncx.NewSingleFlight()
stats = cache.NewStat("mongoc") stats = cache.NewStat("mongoc")
) )

@ -17,8 +17,8 @@ var (
// ErrNotFound is an alias of sqlx.ErrNotFound. // ErrNotFound is an alias of sqlx.ErrNotFound.
ErrNotFound = sqlx.ErrNotFound ErrNotFound = sqlx.ErrNotFound
// can't use one SharedCalls per conn, because multiple conns may share the same cache key. // can't use one SingleFlight per conn, because multiple conns may share the same cache key.
exclusiveCalls = syncx.NewSharedCalls() exclusiveCalls = syncx.NewSingleFlight()
stats = cache.NewStat("sqlc") stats = cache.NewStat("sqlc")
) )

@ -10,7 +10,7 @@ import (
// A ResourceManager is a manager that used to manage resources. // A ResourceManager is a manager that used to manage resources.
type ResourceManager struct { type ResourceManager struct {
resources map[string]io.Closer resources map[string]io.Closer
sharedCalls SharedCalls singleFlight SingleFlight
lock sync.RWMutex lock sync.RWMutex
} }
@ -18,7 +18,7 @@ type ResourceManager struct {
func NewResourceManager() *ResourceManager { func NewResourceManager() *ResourceManager {
return &ResourceManager{ return &ResourceManager{
resources: make(map[string]io.Closer), resources: make(map[string]io.Closer),
sharedCalls: NewSharedCalls(), singleFlight: NewSingleFlight(),
} }
} }
@ -39,7 +39,7 @@ func (manager *ResourceManager) Close() error {
// GetResource returns the resource associated with given key. // GetResource returns the resource associated with given key.
func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) { func (manager *ResourceManager) GetResource(key string, create func() (io.Closer, error)) (io.Closer, error) {
val, err := manager.sharedCalls.Do(key, func() (interface{}, error) { val, err := manager.singleFlight.Do(key, func() (interface{}, error) {
manager.lock.RLock() manager.lock.RLock()
resource, ok := manager.resources[key] resource, ok := manager.resources[key]
manager.lock.RUnlock() manager.lock.RUnlock()

@ -3,13 +3,17 @@ package syncx
import "sync" import "sync"
type ( type (
// SharedCalls lets the concurrent calls with the same key to share the call result. // SharedCalls is an alias of SingleFlight.
// Deprecated: use SingleFlight.
SharedCalls = SingleFlight
// SingleFlight lets the concurrent calls with the same key to share the call result.
// For example, A called F, before it's done, B called F. Then B would not execute F, // For example, A called F, before it's done, B called F. Then B would not execute F,
// and shared the result returned by F which called by A. // and shared the result returned by F which called by A.
// The calls with the same key are dependent, concurrent calls share the returned values. // The calls with the same key are dependent, concurrent calls share the returned values.
// A ------->calls F with key<------------------->returns val // A ------->calls F with key<------------------->returns val
// B --------------------->calls F with key------>returns val // B --------------------->calls F with key------>returns val
SharedCalls interface { SingleFlight interface {
Do(key string, fn func() (interface{}, error)) (interface{}, error) Do(key string, fn func() (interface{}, error)) (interface{}, error)
DoEx(key string, fn func() (interface{}, error)) (interface{}, bool, error) DoEx(key string, fn func() (interface{}, error)) (interface{}, bool, error)
} }
@ -20,20 +24,26 @@ type (
err error err error
} }
sharedGroup struct { flightGroup struct {
calls map[string]*call calls map[string]*call
lock sync.Mutex lock sync.Mutex
} }
) )
// NewSharedCalls returns a SharedCalls. // NewSingleFlight returns a SingleFlight.
func NewSharedCalls() SharedCalls { func NewSingleFlight() SingleFlight {
return &sharedGroup{ return &flightGroup{
calls: make(map[string]*call), calls: make(map[string]*call),
} }
} }
func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) { // NewSharedCalls returns a SingleFlight.
// Deprecated: use NewSingleFlight.
func NewSharedCalls() SingleFlight {
return NewSingleFlight()
}
func (g *flightGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
c, done := g.createCall(key) c, done := g.createCall(key)
if done { if done {
return c.val, c.err return c.val, c.err
@ -43,7 +53,7 @@ func (g *sharedGroup) Do(key string, fn func() (interface{}, error)) (interface{
return c.val, c.err return c.val, c.err
} }
func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) { func (g *flightGroup) DoEx(key string, fn func() (interface{}, error)) (val interface{}, fresh bool, err error) {
c, done := g.createCall(key) c, done := g.createCall(key)
if done { if done {
return c.val, false, c.err return c.val, false, c.err
@ -53,7 +63,7 @@ func (g *sharedGroup) DoEx(key string, fn func() (interface{}, error)) (val inte
return c.val, true, c.err return c.val, true, c.err
} }
func (g *sharedGroup) createCall(key string) (c *call, done bool) { func (g *flightGroup) createCall(key string) (c *call, done bool) {
g.lock.Lock() g.lock.Lock()
if c, ok := g.calls[key]; ok { if c, ok := g.calls[key]; ok {
g.lock.Unlock() g.lock.Unlock()
@ -69,7 +79,7 @@ func (g *sharedGroup) createCall(key string) (c *call, done bool) {
return c, false return c, false
} }
func (g *sharedGroup) makeCall(c *call, key string, fn func() (interface{}, error)) { func (g *flightGroup) makeCall(c *call, key string, fn func() (interface{}, error)) {
defer func() { defer func() {
g.lock.Lock() g.lock.Lock()
delete(g.calls, key) delete(g.calls, key)

@ -10,7 +10,7 @@ import (
) )
func TestExclusiveCallDo(t *testing.T) { func TestExclusiveCallDo(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
v, err := g.Do("key", func() (interface{}, error) { v, err := g.Do("key", func() (interface{}, error) {
return "bar", nil return "bar", nil
}) })
@ -23,7 +23,7 @@ func TestExclusiveCallDo(t *testing.T) {
} }
func TestExclusiveCallDoErr(t *testing.T) { func TestExclusiveCallDoErr(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
someErr := errors.New("some error") someErr := errors.New("some error")
v, err := g.Do("key", func() (interface{}, error) { v, err := g.Do("key", func() (interface{}, error) {
return nil, someErr return nil, someErr
@ -37,7 +37,7 @@ func TestExclusiveCallDoErr(t *testing.T) {
} }
func TestExclusiveCallDoDupSuppress(t *testing.T) { func TestExclusiveCallDoDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
c := make(chan string) c := make(chan string)
var calls int32 var calls int32
fn := func() (interface{}, error) { fn := func() (interface{}, error) {
@ -69,7 +69,7 @@ func TestExclusiveCallDoDupSuppress(t *testing.T) {
} }
func TestExclusiveCallDoDiffDupSuppress(t *testing.T) { func TestExclusiveCallDoDiffDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
broadcast := make(chan struct{}) broadcast := make(chan struct{})
var calls int32 var calls int32
tests := []string{"e", "a", "e", "a", "b", "c", "b", "a", "c", "d", "b", "c", "d"} tests := []string{"e", "a", "e", "a", "b", "c", "b", "a", "c", "d", "b", "c", "d"}
@ -102,7 +102,7 @@ func TestExclusiveCallDoDiffDupSuppress(t *testing.T) {
} }
func TestExclusiveCallDoExDupSuppress(t *testing.T) { func TestExclusiveCallDoExDupSuppress(t *testing.T) {
g := NewSharedCalls() g := NewSingleFlight()
c := make(chan string) c := make(chan string)
var calls int32 var calls int32
fn := func() (interface{}, error) { fn := func() (interface{}, error) {

@ -15,7 +15,7 @@ type RpcProxy struct {
backend string backend string
clients map[string]Client clients map[string]Client
options []internal.ClientOption options []internal.ClientOption
sharedCalls syncx.SharedCalls sharedCalls syncx.SingleFlight
lock sync.Mutex lock sync.Mutex
} }
@ -25,7 +25,7 @@ func NewProxy(backend string, opts ...internal.ClientOption) *RpcProxy {
backend: backend, backend: backend,
clients: make(map[string]Client), clients: make(map[string]Client),
options: opts, options: opts,
sharedCalls: syncx.NewSharedCalls(), sharedCalls: syncx.NewSingleFlight(),
} }
} }

Loading…
Cancel
Save