// Returns a connection for the given key or given address, depending on which // is set. Even if addr is given the returned addr may be different, if that // addr didn't have an associated pool and one couldn't be created func (c *Cluster) getConn(key, addr string) (string, *redis.Client, error) { respCh := make(chan *connTup) c.callCh <- func(c *Cluster) { if key != "" { addr = c.addrForKeyInner(key) } var pool *pool.Pool if addr == "" { addr, pool = c.getRandomPoolInner() } else { var ok bool var err error if pool, ok = c.pools[addr]; !ok { pool, err = c.newPool(addr, false) if err != nil { addr, pool = c.getRandomPoolInner() } else { c.pools[addr] = pool } } } if pool == nil { respCh <- &connTup{err: errNoPools} return } conn, err := pool.Get() // If there's an error try one more time retrieving from a random pool // before bailing if err != nil { addr, pool = c.getRandomPoolInner() if pool == nil { respCh <- &connTup{err: errNoPools} return } conn, err = pool.Get() if err != nil { respCh <- &connTup{err: err} return } } respCh <- &connTup{addr, conn, nil} } r := <-respCh return r.addr, r.conn, r.err }
func (c *Cluster) resetInnerUsingPool(addr string, p *pool.Pool) error { // If we move the throttle check to be in here we'll have to fix the test in // TestReset, since it depends on being able to call Reset right after // initializing the cluster client, err := p.Get() if err != nil { return err } defer client.Close() pools := map[string]*pool.Pool{ addr: p, } r := client.Cmd("CLUSTER", "SLOTS") if r.Err != nil { return r.Err } else if r.Elems == nil || len(r.Elems) < 1 { return errors.New("malformed CLUSTER SLOTS response") } var start, end, port int var ip, slotAddr string var slotPool *pool.Pool var ok bool for _, slotGroup := range r.Elems { if start, err = slotGroup.Elems[0].Int(); err != nil { return err } if end, err = slotGroup.Elems[1].Int(); err != nil { return err } if ip, err = slotGroup.Elems[2].Elems[0].Str(); err != nil { return err } if port, err = slotGroup.Elems[2].Elems[1].Int(); err != nil { return err } // cluster slots returns a blank ip for the node we're currently // connected to. I guess the node doesn't know its own ip? I guess that // makes sense if ip == "" { slotAddr = addr } else { slotAddr = ip + ":" + strconv.Itoa(port) } for i := start; i <= end; i++ { c.mapping[i] = slotAddr } if slotPool, ok = c.pools[slotAddr]; ok { pools[slotAddr] = slotPool } else { slotPool, err = c.newPool(slotAddr, true) if err != nil { return err } pools[slotAddr] = slotPool } } for addr := range c.pools { if _, ok := pools[addr]; !ok { c.pools[addr].Empty() delete(c.poolThrottles, addr) } } c.pools = pools return nil }