forked from mirror/redis
Merge pull request #167 from go-redis/fix/clarify-thread-safety
Clarify thread safety. Fixes #166.
This commit is contained in:
commit
eef3fd78ef
|
@ -9,6 +9,9 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// ClusterClient is a Redis Cluster client representing a pool of zero
|
||||
// or more underlying connections. It's safe for concurrent use by
|
||||
// multiple goroutines.
|
||||
type ClusterClient struct {
|
||||
commandable
|
||||
|
||||
|
@ -26,7 +29,7 @@ type ClusterClient struct {
|
|||
reloading uint32
|
||||
}
|
||||
|
||||
// NewClusterClient returns a new Redis Cluster client as described in
|
||||
// NewClusterClient returns a Redis Cluster client as described in
|
||||
// http://redis.io/topics/cluster-spec.
|
||||
func NewClusterClient(opt *ClusterOptions) *ClusterClient {
|
||||
client := &ClusterClient{
|
||||
|
@ -43,8 +46,8 @@ func NewClusterClient(opt *ClusterOptions) *ClusterClient {
|
|||
|
||||
// Close closes the cluster client, releasing any open resources.
|
||||
//
|
||||
// It is rare to Close a Client, as the Client is meant to be
|
||||
// long-lived and shared between many goroutines.
|
||||
// It is rare to Close a ClusterClient, as the ClusterClient is meant
|
||||
// to be long-lived and shared between many goroutines.
|
||||
func (c *ClusterClient) Close() error {
|
||||
defer c.clientsMx.Unlock()
|
||||
c.clientsMx.Lock()
|
||||
|
|
|
@ -10,7 +10,8 @@ type ClusterPipeline struct {
|
|||
}
|
||||
|
||||
// Pipeline creates a new pipeline which is able to execute commands
|
||||
// against multiple shards.
|
||||
// against multiple shards. It's NOT safe for concurrent use by
|
||||
// multiple goroutines.
|
||||
func (c *ClusterClient) Pipeline() *ClusterPipeline {
|
||||
pipe := &ClusterPipeline{
|
||||
cluster: c,
|
||||
|
@ -82,7 +83,7 @@ func (pipe *ClusterPipeline) Exec() (cmds []Cmder, retErr error) {
|
|||
return cmds, retErr
|
||||
}
|
||||
|
||||
// Close marks the pipeline as closed
|
||||
// Close closes the pipeline, releasing any open resources.
|
||||
func (pipe *ClusterPipeline) Close() error {
|
||||
pipe.Discard()
|
||||
pipe.closed = true
|
||||
|
|
3
multi.go
3
multi.go
|
@ -9,7 +9,8 @@ import (
|
|||
var errDiscard = errors.New("redis: Discard can be used only inside Exec")
|
||||
|
||||
// Multi implements Redis transactions as described in
|
||||
// http://redis.io/topics/transactions.
|
||||
// http://redis.io/topics/transactions. It's NOT safe for concurrent
|
||||
// use by multiple goroutines.
|
||||
type Multi struct {
|
||||
commandable
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package redis
|
||||
|
||||
// Pipeline implements pipelining as described in
|
||||
// http://redis.io/topics/pipelining.
|
||||
//
|
||||
// Pipeline is not thread-safe.
|
||||
// http://redis.io/topics/pipelining. It's NOT safe for concurrent use
|
||||
// by multiple goroutines.
|
||||
type Pipeline struct {
|
||||
commandable
|
||||
|
||||
|
@ -36,6 +35,7 @@ func (pipe *Pipeline) process(cmd Cmder) {
|
|||
pipe.cmds = append(pipe.cmds, cmd)
|
||||
}
|
||||
|
||||
// Close closes the pipeline, releasing any open resources.
|
||||
func (pipe *Pipeline) Close() error {
|
||||
pipe.Discard()
|
||||
pipe.closed = true
|
||||
|
|
|
@ -15,7 +15,8 @@ func (c *Client) Publish(channel, message string) *IntCmd {
|
|||
}
|
||||
|
||||
// PubSub implements Pub/Sub commands as described in
|
||||
// http://redis.io/topics/pubsub.
|
||||
// http://redis.io/topics/pubsub. It's NOT safe for concurrent use by
|
||||
// multiple goroutines.
|
||||
type PubSub struct {
|
||||
*baseClient
|
||||
|
||||
|
|
7
redis.go
7
redis.go
|
@ -80,6 +80,9 @@ func (c *baseClient) process(cmd Cmder) {
|
|||
}
|
||||
|
||||
// Close closes the client, releasing any open resources.
|
||||
//
|
||||
// It is rare to Close a Client, as the Client is meant to be
|
||||
// long-lived and shared between many goroutines.
|
||||
func (c *baseClient) Close() error {
|
||||
return c.connPool.Close()
|
||||
}
|
||||
|
@ -173,6 +176,9 @@ func (opt *Options) getIdleTimeout() time.Duration {
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Client is a Redis client representing a pool of zero or more
|
||||
// underlying connections. It's safe for concurrent use by multiple
|
||||
// goroutines.
|
||||
type Client struct {
|
||||
*baseClient
|
||||
commandable
|
||||
|
@ -186,6 +192,7 @@ func newClient(opt *Options, pool pool) *Client {
|
|||
}
|
||||
}
|
||||
|
||||
// NewClient returns a client to the Redis Server specified by Options.
|
||||
func NewClient(opt *Options) *Client {
|
||||
pool := newConnPool(opt)
|
||||
return newClient(opt, pool)
|
||||
|
|
11
ring.go
11
ring.go
|
@ -92,7 +92,8 @@ func (shard *ringShard) Vote(up bool) bool {
|
|||
}
|
||||
|
||||
// Ring is a Redis client that uses constistent hashing to distribute
|
||||
// keys across multiple Redis servers (shards).
|
||||
// keys across multiple Redis servers (shards). It's safe for
|
||||
// concurrent use by multiple goroutines.
|
||||
//
|
||||
// It monitors the state of each shard and removes dead shards from
|
||||
// the ring. When shard comes online it is added back to the ring. This
|
||||
|
@ -215,8 +216,8 @@ func (ring *Ring) heartbeat() {
|
|||
|
||||
// Close closes the ring client, releasing any open resources.
|
||||
//
|
||||
// It is rare to Close a Client, as the Client is meant to be
|
||||
// long-lived and shared between many goroutines.
|
||||
// It is rare to Close a Ring, as the Ring is meant to be long-lived
|
||||
// and shared between many goroutines.
|
||||
func (ring *Ring) Close() (retErr error) {
|
||||
defer ring.mx.Unlock()
|
||||
ring.mx.Lock()
|
||||
|
@ -238,7 +239,8 @@ func (ring *Ring) Close() (retErr error) {
|
|||
}
|
||||
|
||||
// RingPipeline creates a new pipeline which is able to execute commands
|
||||
// against multiple shards.
|
||||
// against multiple shards. It's NOT safe for concurrent use by
|
||||
// multiple goroutines.
|
||||
type RingPipeline struct {
|
||||
commandable
|
||||
|
||||
|
@ -342,6 +344,7 @@ func (pipe *RingPipeline) Exec() (cmds []Cmder, retErr error) {
|
|||
return cmds, retErr
|
||||
}
|
||||
|
||||
// Close closes the pipeline, releasing any open resources.
|
||||
func (pipe *RingPipeline) Close() error {
|
||||
pipe.Discard()
|
||||
pipe.closed = true
|
||||
|
|
|
@ -54,8 +54,9 @@ func (opt *FailoverOptions) options() *Options {
|
|||
}
|
||||
}
|
||||
|
||||
// NewFailoverClient returns a Redis client with automatic failover
|
||||
// capabilities using Redis Sentinel.
|
||||
// NewFailoverClient returns a Redis client that uses Redis Sentinel
|
||||
// for automatic failover. It's safe for concurrent use by multiple
|
||||
// goroutines.
|
||||
func NewFailoverClient(failoverOpt *FailoverOptions) *Client {
|
||||
opt := failoverOpt.options()
|
||||
failover := &sentinelFailover{
|
||||
|
|
Loading…
Reference in New Issue