func (pool *ConnectionPool) GetSession(username, password string) (*Session, error) {
	var conn *connection = nil
	var err error = nil
	const retryTimes = 3
	for i := 0; i < retryTimes; i++ {
		conn, err = pool.getIdleConn()
		if err == nil {
			break
		}
	}
	if conn == nil {
		return nil, err
	}
	resp, err := conn.authenticate(username, password)
	if err != nil || resp.GetErrorCode() != nebula.ErrorCode_SUCCEEDED {
		pool.rwLock.Lock()
		defer pool.rwLock.Unlock()
		removeFromList(&pool.activeConnectionQueue, conn)
		pool.idleConnectionQueue.PushBack(conn)
		return nil, err
	}
	sessID := resp.GetSessionID()
	timezoneOffset := resp.GetTimeZoneOffsetSeconds()
	timezoneName := resp.GetTimeZoneName()
	newSession := Session{
		sessionID:    sessID,
		connection:   conn,
		connPool:     pool,
		log:          pool.log,
		timezoneInfo: timezoneInfo{timezoneOffset, timezoneName},
	}
	return &newSession, nil
}
GetSession authenticates the username and password.
It returns a session if the authentication succeed.
package nebula_go
import (
	"container/list"
	"crypto/tls"
	"fmt"
	"sync"
	"time"
	"github.com/vesoft-inc/nebula-go/v2/nebula"
)
type ConnectionPool struct {
	idleConnectionQueue   list.List
	activeConnectionQueue list.List
	addresses             []HostAddress
	conf                  PoolConfig
	hostIndex             int
	log                   Logger
	rwLock                sync.RWMutex
	cleanerChan           chan struct{}  
	closed                bool
	sslConfig             *tls.Config
}
func NewConnectionPool(addresses []HostAddress, conf PoolConfig, log Logger) (*ConnectionPool, error) {
	return NewSslConnectionPool(addresses, conf, nil, log)
}
func NewSslConnectionPool(addresses []HostAddress, conf PoolConfig, sslConfig *tls.Config, log Logger) (*ConnectionPool, error) {
	convAddress, err := DomainToIP(addresses)
	if err != nil {
		return nil, fmt.Errorf("failed to find IP, error: %s ", err.Error())
	}
	if len(convAddress) == 0 {
		return nil, fmt.Errorf("failed to initialize connection pool: illegal address input")
	}
	conf.validateConf(log)
	newPool := &ConnectionPool{
		conf:      conf,
		log:       log,
		addresses: convAddress,
		hostIndex: 0,
		sslConfig: sslConfig,
	}
	if err = newPool.initPool(); err != nil {
		return nil, err
	}
	newPool.startCleaner()
	return newPool, nil
}
func (pool *ConnectionPool) initPool() error {
	if err := pool.checkAddresses(); err != nil {
		return fmt.Errorf("failed to open connection, error: %s ", err.Error())
	}
	for i := 0; i < pool.conf.MinConnPoolSize; i++ {
		newConn := newConnection(pool.addresses[i%len(pool.addresses)])
		if err := newConn.openSSL(newConn.severAddress, pool.conf.TimeOut, pool.sslConfig); err != nil {
			idleLen := pool.idleConnectionQueue.Len()
			for i := 0; i < idleLen; i++ {
				pool.idleConnectionQueue.Front().Value.(*connection).close()
				pool.idleConnectionQueue.Remove(pool.idleConnectionQueue.Front())
			}
			return fmt.Errorf("failed to open connection, error: %s ", err.Error())
		}
		pool.idleConnectionQueue.PushBack(newConn)
	}
	return nil
}