forked from mirror/redis
Add WrapProcessPipeline
This commit is contained in:
parent
2c11cbf01a
commit
8b4fa6d443
42
cluster.go
42
cluster.go
|
@ -445,6 +445,10 @@ type ClusterClient struct {
|
||||||
cmdsInfoOnce internal.Once
|
cmdsInfoOnce internal.Once
|
||||||
cmdsInfo map[string]*CommandInfo
|
cmdsInfo map[string]*CommandInfo
|
||||||
|
|
||||||
|
process func(Cmder) error
|
||||||
|
processPipeline func([]Cmder) error
|
||||||
|
processTxPipeline func([]Cmder) error
|
||||||
|
|
||||||
// Reports whether slots reloading is in progress.
|
// Reports whether slots reloading is in progress.
|
||||||
reloading uint32
|
reloading uint32
|
||||||
}
|
}
|
||||||
|
@ -458,7 +462,12 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
|
||||||
opt: opt,
|
opt: opt,
|
||||||
nodes: newClusterNodes(opt),
|
nodes: newClusterNodes(opt),
|
||||||
}
|
}
|
||||||
c.setProcessor(c.Process)
|
|
||||||
|
c.process = c.defaultProcess
|
||||||
|
c.processPipeline = c.defaultProcessPipeline
|
||||||
|
c.processTxPipeline = c.defaultProcessTxPipeline
|
||||||
|
|
||||||
|
c.cmdable.setProcessor(c.Process)
|
||||||
|
|
||||||
// Add initial nodes.
|
// Add initial nodes.
|
||||||
for _, addr := range opt.Addrs {
|
for _, addr := range opt.Addrs {
|
||||||
|
@ -628,7 +637,20 @@ func (c *ClusterClient) Close() error {
|
||||||
return c.nodes.Close()
|
return c.nodes.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClusterClient) WrapProcess(
|
||||||
|
fn func(oldProcess func(Cmder) error) func(Cmder) error,
|
||||||
|
) {
|
||||||
|
c.process = fn(c.process)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) Process(cmd Cmder) error {
|
func (c *ClusterClient) Process(cmd Cmder) error {
|
||||||
|
if c.process != nil {
|
||||||
|
return c.process(cmd)
|
||||||
|
}
|
||||||
|
return c.defaultProcess(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClusterClient) defaultProcess(cmd Cmder) error {
|
||||||
state, err := c.state()
|
state, err := c.state()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.setErr(err)
|
cmd.setErr(err)
|
||||||
|
@ -910,9 +932,9 @@ func (c *ClusterClient) reaper(idleCheckFrequency time.Duration) {
|
||||||
|
|
||||||
func (c *ClusterClient) Pipeline() Pipeliner {
|
func (c *ClusterClient) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExec,
|
exec: c.processPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +942,13 @@ func (c *ClusterClient) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
return c.Pipeline().Pipelined(fn)
|
return c.Pipeline().Pipelined(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) pipelineExec(cmds []Cmder) error {
|
func (c *ClusterClient) WrapProcessPipeline(
|
||||||
|
fn func(oldProcess func([]Cmder) error) func([]Cmder) error,
|
||||||
|
) {
|
||||||
|
c.processPipeline = fn(c.processPipeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClusterClient) defaultProcessPipeline(cmds []Cmder) error {
|
||||||
cmdsMap, err := c.mapCmdsByNode(cmds)
|
cmdsMap, err := c.mapCmdsByNode(cmds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setCmdsErr(cmds, err)
|
setCmdsErr(cmds, err)
|
||||||
|
@ -1064,9 +1092,9 @@ func (c *ClusterClient) checkMovedErr(
|
||||||
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
||||||
func (c *ClusterClient) TxPipeline() Pipeliner {
|
func (c *ClusterClient) TxPipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.txPipelineExec,
|
exec: c.processTxPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,7 +1102,7 @@ func (c *ClusterClient) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
return c.TxPipeline().Pipelined(fn)
|
return c.TxPipeline().Pipelined(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClusterClient) txPipelineExec(cmds []Cmder) error {
|
func (c *ClusterClient) defaultProcessTxPipeline(cmds []Cmder) error {
|
||||||
state, err := c.state()
|
state, err := c.state()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -2,58 +2,47 @@ package redis_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-redis/redis"
|
"github.com/go-redis/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Example_instrumentation() {
|
func Example_instrumentation() {
|
||||||
ring := redis.NewRing(&redis.RingOptions{
|
cl := redis.NewClient(&redis.Options{
|
||||||
Addrs: map[string]string{
|
Addr: ":6379",
|
||||||
"shard1": ":6379",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
ring.ForEachShard(func(client *redis.Client) error {
|
cl.WrapProcess(func(old func(cmd redis.Cmder) error) func(cmd redis.Cmder) error {
|
||||||
wrapRedisProcess(client)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
for {
|
|
||||||
ring.Ping()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapRedisProcess(client *redis.Client) {
|
|
||||||
const precision = time.Microsecond
|
|
||||||
var count, avgDur uint32
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for range time.Tick(3 * time.Second) {
|
|
||||||
n := atomic.LoadUint32(&count)
|
|
||||||
dur := time.Duration(atomic.LoadUint32(&avgDur)) * precision
|
|
||||||
fmt.Printf("%s: processed=%d avg_dur=%s\n", client, n, dur)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
client.WrapProcess(func(oldProcess func(redis.Cmder) error) func(redis.Cmder) error {
|
|
||||||
return func(cmd redis.Cmder) error {
|
return func(cmd redis.Cmder) error {
|
||||||
start := time.Now()
|
fmt.Printf("starting processing: <%s>\n", cmd)
|
||||||
err := oldProcess(cmd)
|
err := old(cmd)
|
||||||
dur := time.Since(start)
|
fmt.Printf("finished processing: <%s>\n", cmd)
|
||||||
|
|
||||||
const decay = float64(1) / 100
|
|
||||||
ms := float64(dur / precision)
|
|
||||||
for {
|
|
||||||
avg := atomic.LoadUint32(&avgDur)
|
|
||||||
newAvg := uint32((1-decay)*float64(avg) + decay*ms)
|
|
||||||
if atomic.CompareAndSwapUint32(&avgDur, avg, newAvg) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
atomic.AddUint32(&count, 1)
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
cl.Ping()
|
||||||
|
// Output: starting processing: <ping: >
|
||||||
|
// finished processing: <ping: PONG>
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_Pipeline_instrumentation() {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: ":6379",
|
||||||
|
})
|
||||||
|
|
||||||
|
client.WrapProcessPipeline(func(old func([]redis.Cmder) error) func([]redis.Cmder) error {
|
||||||
|
return func(cmds []redis.Cmder) error {
|
||||||
|
fmt.Printf("pipeline starting processing: %v\n", cmds)
|
||||||
|
err := old(cmds)
|
||||||
|
fmt.Printf("pipeline finished processing: %v\n", cmds)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client.Pipelined(func(pipe redis.Pipeliner) error {
|
||||||
|
pipe.Ping()
|
||||||
|
pipe.Ping()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
// Output: pipeline starting processing: [ping: ping: ]
|
||||||
|
// pipeline finished processing: [ping: PONG ping: PONG]
|
||||||
}
|
}
|
||||||
|
|
104
redis.go
104
redis.go
|
@ -22,6 +22,12 @@ func SetLogger(logger *log.Logger) {
|
||||||
internal.Logger = logger
|
internal.Logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *baseClient) init() {
|
||||||
|
c.process = c.defaultProcess
|
||||||
|
c.processPipeline = c.defaultProcessPipeline
|
||||||
|
c.processTxPipeline = c.defaultProcessTxPipeline
|
||||||
|
}
|
||||||
|
|
||||||
func (c *baseClient) String() string {
|
func (c *baseClient) String() string {
|
||||||
return fmt.Sprintf("Redis<%s db:%d>", c.getAddr(), c.opt.DB)
|
return fmt.Sprintf("Redis<%s db:%d>", c.getAddr(), c.opt.DB)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +91,8 @@ func (c *baseClient) initConn(cn *pool.Conn) error {
|
||||||
connPool: pool.NewSingleConnPool(cn),
|
connPool: pool.NewSingleConnPool(cn),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
conn.setProcessor(conn.Process)
|
conn.baseClient.init()
|
||||||
|
conn.statefulCmdable.setProcessor(conn.Process)
|
||||||
|
|
||||||
_, err := conn.Pipelined(func(pipe Pipeliner) error {
|
_, err := conn.Pipelined(func(pipe Pipeliner) error {
|
||||||
if c.opt.Password != "" {
|
if c.opt.Password != "" {
|
||||||
|
@ -117,14 +124,11 @@ func (c *baseClient) initConn(cn *pool.Conn) error {
|
||||||
// an input and returns the new wrapper process func. createWrapper should
|
// an input and returns the new wrapper process func. createWrapper should
|
||||||
// use call the old process func within the new process func.
|
// use call the old process func within the new process func.
|
||||||
func (c *baseClient) WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error) {
|
func (c *baseClient) WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error) {
|
||||||
c.process = fn(c.defaultProcess)
|
c.process = fn(c.process)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) Process(cmd Cmder) error {
|
func (c *baseClient) Process(cmd Cmder) error {
|
||||||
if c.process != nil {
|
return c.process(cmd)
|
||||||
return c.process(cmd)
|
|
||||||
}
|
|
||||||
return c.defaultProcess(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) defaultProcess(cmd Cmder) error {
|
func (c *baseClient) defaultProcess(cmd Cmder) error {
|
||||||
|
@ -198,35 +202,48 @@ func (c *baseClient) getAddr() string {
|
||||||
return c.opt.Addr
|
return c.opt.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *baseClient) WrapProcessPipeline(
|
||||||
|
fn func(oldProcess func([]Cmder) error) func([]Cmder) error,
|
||||||
|
) {
|
||||||
|
c.processPipeline = fn(c.processPipeline)
|
||||||
|
c.processTxPipeline = fn(c.processTxPipeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseClient) defaultProcessPipeline(cmds []Cmder) error {
|
||||||
|
return c.generalProcessPipeline(cmds, c.pipelineProcessCmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *baseClient) defaultProcessTxPipeline(cmds []Cmder) error {
|
||||||
|
return c.generalProcessPipeline(cmds, c.txPipelineProcessCmds)
|
||||||
|
}
|
||||||
|
|
||||||
type pipelineProcessor func(*pool.Conn, []Cmder) (bool, error)
|
type pipelineProcessor func(*pool.Conn, []Cmder) (bool, error)
|
||||||
|
|
||||||
func (c *baseClient) pipelineExecer(p pipelineProcessor) pipelineExecer {
|
func (c *baseClient) generalProcessPipeline(cmds []Cmder, p pipelineProcessor) error {
|
||||||
return func(cmds []Cmder) error {
|
for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
|
||||||
for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
|
if attempt > 0 {
|
||||||
if attempt > 0 {
|
time.Sleep(c.retryBackoff(attempt))
|
||||||
time.Sleep(c.retryBackoff(attempt))
|
}
|
||||||
}
|
|
||||||
|
cn, _, err := c.getConn()
|
||||||
cn, _, err := c.getConn()
|
if err != nil {
|
||||||
if err != nil {
|
setCmdsErr(cmds, err)
|
||||||
setCmdsErr(cmds, err)
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
canRetry, err := p(cn, cmds)
|
||||||
canRetry, err := p(cn, cmds)
|
|
||||||
|
if err == nil || internal.IsRedisError(err) {
|
||||||
if err == nil || internal.IsRedisError(err) {
|
_ = c.connPool.Put(cn)
|
||||||
_ = c.connPool.Put(cn)
|
break
|
||||||
break
|
}
|
||||||
}
|
_ = c.connPool.Remove(cn)
|
||||||
_ = c.connPool.Remove(cn)
|
|
||||||
|
if !canRetry || !internal.IsRetryableError(err, true) {
|
||||||
if !canRetry || !internal.IsRetryableError(err, true) {
|
break
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return firstCmdsErr(cmds)
|
|
||||||
}
|
}
|
||||||
|
return firstCmdsErr(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *baseClient) pipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
func (c *baseClient) pipelineProcessCmds(cn *pool.Conn, cmds []Cmder) (bool, error) {
|
||||||
|
@ -324,14 +341,15 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient(opt *Options, pool pool.Pooler) *Client {
|
func newClient(opt *Options, pool pool.Pooler) *Client {
|
||||||
client := Client{
|
c := Client{
|
||||||
baseClient: baseClient{
|
baseClient: baseClient{
|
||||||
opt: opt,
|
opt: opt,
|
||||||
connPool: pool,
|
connPool: pool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
client.setProcessor(client.Process)
|
c.baseClient.init()
|
||||||
return &client
|
c.cmdable.setProcessor(c.Process)
|
||||||
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a client to the Redis Server specified by Options.
|
// NewClient returns a client to the Redis Server specified by Options.
|
||||||
|
@ -343,7 +361,7 @@ func NewClient(opt *Options) *Client {
|
||||||
func (c *Client) copy() *Client {
|
func (c *Client) copy() *Client {
|
||||||
c2 := new(Client)
|
c2 := new(Client)
|
||||||
*c2 = *c
|
*c2 = *c
|
||||||
c2.setProcessor(c2.Process)
|
c2.cmdable.setProcessor(c2.Process)
|
||||||
return c2
|
return c2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,9 +384,9 @@ func (c *Client) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
|
|
||||||
func (c *Client) Pipeline() Pipeliner {
|
func (c *Client) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExecer(c.pipelineProcessCmds),
|
exec: c.processPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,9 +397,9 @@ func (c *Client) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
||||||
func (c *Client) TxPipeline() Pipeliner {
|
func (c *Client) TxPipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExecer(c.txPipelineProcessCmds),
|
exec: c.processTxPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,9 +448,9 @@ func (c *Conn) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
|
|
||||||
func (c *Conn) Pipeline() Pipeliner {
|
func (c *Conn) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExecer(c.pipelineProcessCmds),
|
exec: c.processPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,8 +461,8 @@ func (c *Conn) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
// TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC.
|
||||||
func (c *Conn) TxPipeline() Pipeliner {
|
func (c *Conn) TxPipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExecer(c.txPipelineProcessCmds),
|
exec: c.processTxPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,10 @@ type baseClient struct {
|
||||||
connPool pool.Pooler
|
connPool pool.Pooler
|
||||||
opt *Options
|
opt *Options
|
||||||
|
|
||||||
process func(Cmder) error
|
process func(Cmder) error
|
||||||
|
processPipeline func([]Cmder) error
|
||||||
|
processTxPipeline func([]Cmder) error
|
||||||
|
|
||||||
onClose func() error // hook called when client is closed
|
onClose func() error // hook called when client is closed
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
|
@ -10,6 +10,9 @@ type baseClient struct {
|
||||||
connPool pool.Pooler
|
connPool pool.Pooler
|
||||||
opt *Options
|
opt *Options
|
||||||
|
|
||||||
process func(Cmder) error
|
process func(Cmder) error
|
||||||
|
processPipeline func([]Cmder) error
|
||||||
|
processTxPipeline func([]Cmder) error
|
||||||
|
|
||||||
onClose func() error // hook called when client is closed
|
onClose func() error // hook called when client is closed
|
||||||
}
|
}
|
||||||
|
|
29
ring.go
29
ring.go
|
@ -150,6 +150,8 @@ type Ring struct {
|
||||||
shards map[string]*ringShard
|
shards map[string]*ringShard
|
||||||
shardsList []*ringShard
|
shardsList []*ringShard
|
||||||
|
|
||||||
|
processPipeline func([]Cmder) error
|
||||||
|
|
||||||
cmdsInfoOnce internal.Once
|
cmdsInfoOnce internal.Once
|
||||||
cmdsInfo map[string]*CommandInfo
|
cmdsInfo map[string]*CommandInfo
|
||||||
|
|
||||||
|
@ -158,7 +160,9 @@ type Ring struct {
|
||||||
|
|
||||||
func NewRing(opt *RingOptions) *Ring {
|
func NewRing(opt *RingOptions) *Ring {
|
||||||
const nreplicas = 100
|
const nreplicas = 100
|
||||||
|
|
||||||
opt.init()
|
opt.init()
|
||||||
|
|
||||||
ring := &Ring{
|
ring := &Ring{
|
||||||
opt: opt,
|
opt: opt,
|
||||||
nreplicas: nreplicas,
|
nreplicas: nreplicas,
|
||||||
|
@ -166,13 +170,17 @@ func NewRing(opt *RingOptions) *Ring {
|
||||||
hash: consistenthash.New(nreplicas, nil),
|
hash: consistenthash.New(nreplicas, nil),
|
||||||
shards: make(map[string]*ringShard),
|
shards: make(map[string]*ringShard),
|
||||||
}
|
}
|
||||||
ring.setProcessor(ring.Process)
|
ring.processPipeline = ring.defaultProcessPipeline
|
||||||
|
ring.cmdable.setProcessor(ring.Process)
|
||||||
|
|
||||||
for name, addr := range opt.Addrs {
|
for name, addr := range opt.Addrs {
|
||||||
clopt := opt.clientOptions()
|
clopt := opt.clientOptions()
|
||||||
clopt.Addr = addr
|
clopt.Addr = addr
|
||||||
ring.addShard(name, NewClient(clopt))
|
ring.addShard(name, NewClient(clopt))
|
||||||
}
|
}
|
||||||
|
|
||||||
go ring.heartbeat()
|
go ring.heartbeat()
|
||||||
|
|
||||||
return ring
|
return ring
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,6 +362,13 @@ func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) {
|
||||||
return c.shardByKey(firstKey)
|
return c.shardByKey(firstKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Ring) WrapProcess(fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error) {
|
||||||
|
c.ForEachShard(func(c *Client) error {
|
||||||
|
c.WrapProcess(fn)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Ring) Process(cmd Cmder) error {
|
func (c *Ring) Process(cmd Cmder) error {
|
||||||
shard, err := c.cmdShard(cmd)
|
shard, err := c.cmdShard(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -436,9 +451,9 @@ func (c *Ring) Close() error {
|
||||||
|
|
||||||
func (c *Ring) Pipeline() Pipeliner {
|
func (c *Ring) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExec,
|
exec: c.processPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.cmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +461,13 @@ func (c *Ring) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) {
|
||||||
return c.Pipeline().Pipelined(fn)
|
return c.Pipeline().Pipelined(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ring) pipelineExec(cmds []Cmder) error {
|
func (c *Ring) WrapProcessPipeline(
|
||||||
|
fn func(oldProcess func([]Cmder) error) func([]Cmder) error,
|
||||||
|
) {
|
||||||
|
c.processPipeline = fn(c.processPipeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Ring) defaultProcessPipeline(cmds []Cmder) error {
|
||||||
cmdsMap := make(map[string][]Cmder)
|
cmdsMap := make(map[string][]Cmder)
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
cmdInfo := c.cmdInfo(cmd.Name())
|
cmdInfo := c.cmdInfo(cmd.Name())
|
||||||
|
|
14
sentinel.go
14
sentinel.go
|
@ -76,7 +76,7 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
|
||||||
opt: opt,
|
opt: opt,
|
||||||
}
|
}
|
||||||
|
|
||||||
client := Client{
|
c := Client{
|
||||||
baseClient: baseClient{
|
baseClient: baseClient{
|
||||||
opt: opt,
|
opt: opt,
|
||||||
connPool: failover.Pool(),
|
connPool: failover.Pool(),
|
||||||
|
@ -86,9 +86,10 @@ func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
client.setProcessor(client.Process)
|
c.baseClient.init()
|
||||||
|
c.setProcessor(c.Process)
|
||||||
|
|
||||||
return &client
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -100,14 +101,15 @@ type sentinelClient struct {
|
||||||
|
|
||||||
func newSentinel(opt *Options) *sentinelClient {
|
func newSentinel(opt *Options) *sentinelClient {
|
||||||
opt.init()
|
opt.init()
|
||||||
client := sentinelClient{
|
c := sentinelClient{
|
||||||
baseClient: baseClient{
|
baseClient: baseClient{
|
||||||
opt: opt,
|
opt: opt,
|
||||||
connPool: newConnPool(opt),
|
connPool: newConnPool(opt),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
client.cmdable = cmdable{client.Process}
|
c.baseClient.init()
|
||||||
return &client
|
c.cmdable.setProcessor(c.Process)
|
||||||
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sentinelClient) PubSub() *PubSub {
|
func (c *sentinelClient) PubSub() *PubSub {
|
||||||
|
|
7
tx.go
7
tx.go
|
@ -24,7 +24,8 @@ func (c *Client) newTx() *Tx {
|
||||||
connPool: pool.NewStickyConnPool(c.connPool.(*pool.ConnPool), true),
|
connPool: pool.NewStickyConnPool(c.connPool.(*pool.ConnPool), true),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
tx.setProcessor(tx.Process)
|
tx.baseClient.init()
|
||||||
|
tx.statefulCmdable.setProcessor(tx.Process)
|
||||||
return &tx
|
return &tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +76,9 @@ func (c *Tx) Unwatch(keys ...string) *StatusCmd {
|
||||||
|
|
||||||
func (c *Tx) Pipeline() Pipeliner {
|
func (c *Tx) Pipeline() Pipeliner {
|
||||||
pipe := Pipeline{
|
pipe := Pipeline{
|
||||||
exec: c.pipelineExecer(c.txPipelineProcessCmds),
|
exec: c.processTxPipeline,
|
||||||
}
|
}
|
||||||
pipe.setProcessor(pipe.Process)
|
pipe.statefulCmdable.setProcessor(pipe.Process)
|
||||||
return &pipe
|
return &pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue