Merge pull request #768 from go-redis/fix/for-each-reload-state

cluster: reload state for ForEach functions and every 1 minute
This commit is contained in:
Vladimir Mihailenco 2018-05-21 17:18:30 +03:00 committed by GitHub
commit e3d9f9d1c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 35 additions and 17 deletions

View File

@ -391,16 +391,19 @@ type clusterState struct {
slots [][]*clusterNode slots [][]*clusterNode
generation uint32 generation uint32
createdAt time.Time
} }
func newClusterState( func newClusterState(
nodes *clusterNodes, slots []ClusterSlot, origin string, nodes *clusterNodes, slots []ClusterSlot, origin string,
) (*clusterState, error) { ) (*clusterState, error) {
c := clusterState{ c := clusterState{
nodes: nodes, nodes: nodes,
generation: nodes.NextGeneration(),
slots: make([][]*clusterNode, hashtag.SlotNumber), slots: make([][]*clusterNode, hashtag.SlotNumber),
generation: nodes.NextGeneration(),
createdAt: time.Now(),
} }
isLoopbackOrigin := isLoopbackAddr(origin) isLoopbackOrigin := isLoopbackAddr(origin)
@ -534,8 +537,8 @@ type clusterStateHolder struct {
state atomic.Value state atomic.Value
lastErrMu sync.RWMutex firstErrMu sync.RWMutex
lastErr error firstErr error
reloading uint32 // atomic reloading uint32 // atomic
} }
@ -560,9 +563,11 @@ func (c *clusterStateHolder) Reload() (*clusterState, error) {
func (c *clusterStateHolder) reload() (*clusterState, error) { func (c *clusterStateHolder) reload() (*clusterState, error) {
state, err := c.load() state, err := c.load()
if err != nil { if err != nil {
c.lastErrMu.Lock() c.firstErrMu.Lock()
c.lastErr = err if c.firstErr == nil {
c.lastErrMu.Unlock() c.firstErr = err
}
c.firstErrMu.Unlock()
return nil, err return nil, err
} }
c.state.Store(state) c.state.Store(state)
@ -592,12 +597,16 @@ func (c *clusterStateHolder) LazyReload() {
func (c *clusterStateHolder) Get() (*clusterState, error) { func (c *clusterStateHolder) Get() (*clusterState, error) {
v := c.state.Load() v := c.state.Load()
if v != nil { if v != nil {
return v.(*clusterState), nil state := v.(*clusterState)
if time.Since(state.createdAt) > time.Minute {
c.LazyReload()
}
return state, nil
} }
c.lastErrMu.RLock() c.firstErrMu.RLock()
err := c.lastErr err := c.firstErr
c.lastErrMu.RUnlock() c.firstErrMu.RUnlock()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -930,9 +939,12 @@ func (c *ClusterClient) defaultProcess(cmd Cmder) error {
// ForEachMaster concurrently calls the fn on each master node in the cluster. // ForEachMaster concurrently calls the fn on each master node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error { func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
state, err := c.state.Get() state, err := c.state.Reload()
if err != nil { if err != nil {
return err state, err = c.state.Get()
if err != nil {
return err
}
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@ -963,9 +975,12 @@ func (c *ClusterClient) ForEachMaster(fn func(client *Client) error) error {
// ForEachSlave concurrently calls the fn on each slave node in the cluster. // ForEachSlave concurrently calls the fn on each slave node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error { func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
state, err := c.state.Get() state, err := c.state.Reload()
if err != nil { if err != nil {
return err state, err = c.state.Get()
if err != nil {
return err
}
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@ -996,9 +1011,12 @@ func (c *ClusterClient) ForEachSlave(fn func(client *Client) error) error {
// ForEachNode concurrently calls the fn on each known node in the cluster. // ForEachNode concurrently calls the fn on each known node in the cluster.
// It returns the first error if any. // It returns the first error if any.
func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error { func (c *ClusterClient) ForEachNode(fn func(client *Client) error) error {
state, err := c.state.Get() state, err := c.state.Reload()
if err != nil { if err != nil {
return err state, err = c.state.Get()
if err != nil {
return err
}
} }
var wg sync.WaitGroup var wg sync.WaitGroup