func tcpListen(bind string) { addr, err := net.ResolveTCPAddr("tcp", bind) if err != nil { log.Error("net.ResolveTCPAddr(\"tcp\"), %s) error(%v)", bind, err) panic(err) } l, err := net.ListenTCP("tcp", addr) if err != nil { log.Error("net.ListenTCP(\"tcp4\", \"%s\") error(%v)", bind, err) panic(err) } // free the listener resource defer func() { log.Info("tcp addr: \"%s\" close", bind) if err := l.Close(); err != nil { log.Error("listener.Close() error(%v)", err) } }() // init reader buffer instance rb := newtcpBufCache() for { log.Trace("start accept") conn, err := l.AcceptTCP() if err != nil { log.Error("listener.AcceptTCP() error(%v)", err) continue } if err = conn.SetKeepAlive(Conf.TCPKeepalive); err != nil { log.Error("conn.SetKeepAlive() error(%v)", err) conn.Close() continue } if err = conn.SetReadBuffer(Conf.RcvbufSize); err != nil { log.Error("conn.SetReadBuffer(%d) error(%v)", Conf.RcvbufSize, err) conn.Close() continue } if err = conn.SetWriteBuffer(Conf.SndbufSize); err != nil { log.Error("conn.SetWriteBuffer(%d) error(%v)", Conf.SndbufSize, err) conn.Close() continue } // first packet must sent by client in specified seconds if err = conn.SetReadDeadline(time.Now().Add(fitstPacketTimedoutSec)); err != nil { log.Error("conn.SetReadDeadLine() error(%v)", err) conn.Close() continue } rc := rb.Get() // one connection one routine go handleTCPConn(conn, rc) log.Trace("accept finished") } }
// Get gets a connection. The application must close the returned connection. // This method always returns a valid connection so that applications can defer // error handling to the first use of the connection. func (p *Pool) Get() (interface{}, error) { if p.closed { return nil, ErrPoolClosed } log.Trace("") if timeout := p.IdleTimeout; timeout > 0 { log.Trace("check expire conn start") go func() { //check expire connection for e := p.idle.Front(); e != nil; e = e.Next() { ic := e.Value.(idleConn) if ic.t.Add(timeout).After(time.Now()) { p.mu.Lock() p.idle.Remove(e) p.active -= 1 p.mu.Unlock() p.Close(ic.c) } } }() } log.Trace("Get idle connection") // Get idle connection. for e := p.idle.Back(); e != nil; e = e.Prev() { p.mu.Lock() c := p.idle.Remove(e).(idleConn).c p.mu.Unlock() log.Trace("TestOnBorrow before return old thrift client.") if p.TestOnBorrow(c) != nil { p.active -= 1 p.Close(c) continue } else { log.Trace("return old thrift client.") return c, nil } } log.Trace("exhaust if active count more than MaxActive") // No idle connection, pool exhaust if active count more than MaxActive if p.active >= p.MaxActive { p.mu.Unlock() return nil, ErrPoolExhausted } log.Trace("No idle connection, create new.") // No idle connection, create new. dial := p.Dial p.active += 1 c, err := dial() if err != nil { p.mu.Lock() p.active -= 1 p.mu.Unlock() c = nil } log.Trace("return new thrift client.") return c, err }