From 96e3b358fe2d8c76e51f13b30a74384fe9b331fe Mon Sep 17 00:00:00 2001 From: rfyiamcool Date: Sun, 10 Sep 2023 21:36:57 +0800 Subject: [PATCH 1/3] feat: with fail fast mode for low latency Signed-off-by: rfyiamcool --- mutex.go | 25 +++++++++++++++++++++---- redsync.go | 8 ++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/mutex.go b/mutex.go index e8f5ba2..9cb26d0 100644 --- a/mutex.go +++ b/mutex.go @@ -30,6 +30,7 @@ type Mutex struct { value string until time.Time shuffle bool + failFast bool pools []redis.Pool } @@ -263,7 +264,7 @@ func (m *Mutex) actOnPoolsAsync(actFn func(redis.Pool) (bool, error)) (int, erro err error } - ch := make(chan result) + ch := make(chan result, len(m.pools)) for node, pool := range m.pools { go func(node int, pool redis.Pool) { r := result{node: node} @@ -271,9 +272,13 @@ func (m *Mutex) actOnPoolsAsync(actFn func(redis.Pool) (bool, error)) (int, erro ch <- r }(node, pool) } - n := 0 - var taken []int - var err error + + var ( + n = 0 + taken []int + err error + ) + for range m.pools { r := <-ch if r.statusOK { @@ -284,6 +289,18 @@ func (m *Mutex) actOnPoolsAsync(actFn func(redis.Pool) (bool, error)) (int, erro taken = append(taken, r.node) err = multierror.Append(err, &ErrNodeTaken{Node: r.node}) } + + if m.failFast { + // fast retrun + if n >= m.quorum { + return n, err + } + + // fail fast + if len(taken) >= m.quorum { + return n, &ErrTaken{Nodes: taken} + } + } } if len(taken) >= m.quorum { diff --git a/redsync.go b/redsync.go index 97f3bad..60b0e7b 100644 --- a/redsync.go +++ b/redsync.go @@ -125,6 +125,14 @@ func WithValue(v string) Option { }) } +// With FailFast can be used to quickly acquire and release the locker. We do not need to wait for all redis response results. +// As long as the quorum is met, it will be returned immediately, and requests that have not yet been returned will be processed asynchronously. +func WithFailFast(b bool) Option { + return OptionFunc(func(m *Mutex) { + m.failFast = b + }) +} + // WithShufflePools can be used to shuffle Redis pools to reduce centralized access in concurrent scenarios. func WithShufflePools(b bool) Option { return OptionFunc(func(m *Mutex) { From d21878d5a5eaad2cb843e76fc6fa82a202005cd0 Mon Sep 17 00:00:00 2001 From: rfyiamcool Date: Sun, 10 Sep 2023 22:34:49 +0800 Subject: [PATCH 2/3] feat: with fail fast mode for low latency Signed-off-by: rfyiamcool --- redsync.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/redsync.go b/redsync.go index 60b0e7b..60fdb53 100644 --- a/redsync.go +++ b/redsync.go @@ -125,8 +125,9 @@ func WithValue(v string) Option { }) } -// With FailFast can be used to quickly acquire and release the locker. We do not need to wait for all redis response results. -// As long as the quorum is met, it will be returned immediately, and requests that have not yet been returned will be processed asynchronously. +// WithFailFast can be used to quickly acquire and release the locker when some redis servers are blocking. +// We do not need to wait for all redis servers response. As long as the quorum is met, it will be returned immediately, and requests that have not yet been returned will be processed asynchronously. +// The effect of this parameter is to achieve low latency, avoid redis blocking causing lock/unlock to not return for a long time. func WithFailFast(b bool) Option { return OptionFunc(func(m *Mutex) { m.failFast = b From f672726b9ef34e9e20694e69915a195e2d04c6ee Mon Sep 17 00:00:00 2001 From: rfyiamcool Date: Sun, 10 Sep 2023 22:37:47 +0800 Subject: [PATCH 3/3] feat: with fail fast mode for low latency Signed-off-by: rfyiamcool --- redsync.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redsync.go b/redsync.go index 60fdb53..b65e7b3 100644 --- a/redsync.go +++ b/redsync.go @@ -125,8 +125,8 @@ func WithValue(v string) Option { }) } -// WithFailFast can be used to quickly acquire and release the locker when some redis servers are blocking. -// We do not need to wait for all redis servers response. As long as the quorum is met, it will be returned immediately, and requests that have not yet been returned will be processed asynchronously. +// WithFailFast can be used to quickly acquire and release the locker. +// When some redis servers are blocking, we do not need to wait for all redis servers response. as long as the quorum is met, it will be returned immediately. // The effect of this parameter is to achieve low latency, avoid redis blocking causing lock/unlock to not return for a long time. func WithFailFast(b bool) Option { return OptionFunc(func(m *Mutex) {