예제 #1
0
// 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
}
예제 #2
0
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
}