Merge pull request #167 from go-redis/fix/clarify-thread-safety

Clarify thread safety. Fixes #166.
This commit is contained in:
Vladimir Mihailenco 2015-09-12 09:45:37 +03:00
commit eef3fd78ef
8 changed files with 33 additions and 16 deletions

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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

View File

@ -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{