func (p *pool) disconnect(ctx context.Context) error {
	if !atomic.CompareAndSwapInt32(&p.connected, connected, disconnecting) {
		return ErrPoolDisconnected
	}

	if ctx == nil {
		ctx = context.Background()
	}

	p.conns.Close()
	atomic.AddUint64(&p.generation, 1)

	var err error
	if dl, ok := ctx.Deadline(); ok {
		// If we have a deadline then we interpret it as a request to gracefully shutdown. We wait
		// until either all the connections have landed back in the pool (and have been closed) or
		// until the timer is done.
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()
		timer := time.NewTimer(time.Now().Sub(dl))
		defer timer.Stop()
		for {
			select {
			case <-timer.C:
			case <-ctx.Done():
			case <-ticker.C: // Can we replace this with an actual signal channel? We will know when p.inflight hits zero from the close method.
				p.Lock()
				if len(p.opened) > 0 {
					p.Unlock()
					continue
				}
				p.Unlock()
			}
			break
		}
	}

	// We copy the remaining connections into a slice, then iterate it to close them. This allows us
	// to use a single function to actually clean up and close connections at the expense of a
	// double iteration in the worse case.
	p.Lock()
	toClose := make([]*connection, 0, len(p.opened))
	for _, pc := range p.opened {
		toClose = append(toClose, pc)
	}
	p.Unlock()
	for _, pc := range toClose {
		if p.monitor != nil {
			p.monitor.Event(&event.PoolEvent{
				Type:         event.ConnectionClosed,
				Address:      p.address.String(),
				ConnectionID: pc.poolID,
				Reason:       event.ReasonPoolClosed,
			})
		}
		_ = p.closeConnection(pc) // We don't care about errors while closing the connection.
	}
	atomic.StoreInt32(&p.connected, disconnected)

	if p.monitor != nil {
		p.monitor.Event(&event.PoolEvent{
			Type:    event.PoolClosedEvent,
			Address: p.address.String(),
		})
	}

	return err
}
// disconnect disconnects the pool and closes all connections including those both in and out of the pool
disconnect disconnects the pool and closes all connections including those both in and out of the pool
// disconnect disconnects the pool and closes all connections including those both in and out of the pool
func (p *pool) disconnect(ctx context.Context) error {
	if !atomic.CompareAndSwapInt32(&p.connected, connected, disconnecting) {
		return ErrPoolDisconnected
	}
	if ctx == nil {
		ctx = context.Background()
	}
	p.conns.Close()
	atomic.AddUint64(&p.generation, 1)
	var err error
	if dl, ok := ctx.Deadline(); ok {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()
		timer := time.NewTimer(time.Now().Sub(dl))
		defer timer.Stop()
		for {
			select {
			case <-timer.C:
			case <-ctx.Done():
			case <-ticker.C: 
				p.Lock()
				if len(p.opened) > 0 {
					p.Unlock()
					continue
				}
				p.Unlock()
			}
			break
		}
	}
	p.Lock()
	toClose := make([]*connection, 0, len(p.opened))
	for _, pc := range p.opened {
		toClose = append(toClose, pc)
	}
	p.Unlock()
	for _, pc := range toClose {
		if p.monitor != nil {
			p.monitor.Event(&event.PoolEvent{
				Type:         event.ConnectionClosed,
				Address:      p.address.String(),
				ConnectionID: pc.poolID,
				Reason:       event.ReasonPoolClosed,
			})
		}
		_ = p.closeConnection(pc) 
	}
	atomic.StoreInt32(&p.connected, disconnected)
	if p.monitor != nil {
		p.monitor.Event(&event.PoolEvent{
			Type:    event.PoolClosedEvent,
			Address: p.address.String(),
		})
	}
	return err
}
func ( p * pool ) disconnect ( ctx context . Context ) error { if ! atomic . CompareAndSwapInt32 ( & p . connected , connected , disconnecting ) { return ErrPoolDisconnected } if ctx == nil { ctx = context . Background ( ) } p . conns . Close ( ) atomic . AddUint64 ( & p . generation , 1 ) var err error if dl , ok := ctx . Deadline ( ) ; ok { ticker := time . NewTicker ( 1 * time . Second ) defer ticker . Stop ( ) timer := time . NewTimer ( time . Now ( ) . Sub ( dl ) ) defer timer . Stop ( ) for { select { case <- timer . C : case <- ctx . Done ( ) : case <- ticker . C : p . Lock ( ) if len ( p . opened ) > 0 { p . Unlock ( ) continue } p . Unlock ( ) } break } } p . Lock ( ) toClose := make ( [ ] * connection , 0 , len ( p . opened ) ) for _ , pc := range p . opened { toClose = append ( toClose , pc ) } p . Unlock ( ) for _ , pc := range toClose { if p . monitor != nil { p . monitor . Event ( & event . PoolEvent { Type : event . ConnectionClosed , Address : p . address . String ( ) , ConnectionID : pc . poolID , Reason : event . ReasonPoolClosed , } ) } _ = p . closeConnection ( pc ) } atomic . StoreInt32 ( & p . connected , disconnected ) if p . monitor != nil { p . monitor . Event ( & event . PoolEvent { Type : event . PoolClosedEvent , Address : p . address . String ( ) , } ) } return err }
disconnect disconnects the pool and closes all connections including those both in and out of the pool
disconnect disconnects the pool and closes all connections including those both in and out of the pool
// If we have a deadline then we interpret it as a request to gracefully shutdown. We wait // until either all the connections have landed back in the pool (and have been closed) or // until the timer is done. // Can we replace this with an actual signal channel? We will know when p.inflight hits zero from the close method. // We copy the remaining connections into a slice, then iterate it to close them. This allows us // to use a single function to actually clean up and close connections at the expense of a // double iteration in the worse case. // We don't care about errors while closing the connection.