func (i *DialInfo) poolLimit() int {
	if i.PoolLimit == 0 {
		return DefaultConnectionPoolLimit
	}
	return i.PoolLimit
}
poolLimit returns the configured connection pool size, or
DefaultConnectionPoolLimit.
package mgo
import (
	"crypto/md5"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"encoding/hex"
	"errors"
	"fmt"
	"math"
	"net"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
	"github.com/globalsign/mgo/bson"
)
type Mode int
const (
	Primary Mode = 2
	PrimaryPreferred Mode = 3
	Secondary Mode = 4
	SecondaryPreferred Mode = 5
	Nearest Mode = 6
	Eventual Mode = 0
	Monotonic Mode = 1
	Strong Mode = 2
	DefaultConnectionPoolLimit = 4096
	zeroDuration = time.Duration(0)
)
type Session struct {
	defaultdb        string
	sourcedb         string
	syncTimeout      time.Duration
	consistency      Mode
	creds            []Credential
	dialCred         *Credential
	safeOp           *queryOp
	mgoCluster       *mongoCluster
	slaveSocket      *mongoSocket
	masterSocket     *mongoSocket
	m                sync.RWMutex
	queryConfig      query
	bypassValidation bool
	slaveOk          bool
	dialInfo *DialInfo
}
type Database struct {
	Session *Session
	Name    string
}
type Collection struct {
	Database *Database
	Name     string  
	FullName string  
}
type Query struct {
	m       sync.Mutex
	session *Session
	query    
}
type query struct {
	op       queryOp
	prefetch float64
	limit    int32
}
type getLastError struct {
	CmdName  int         `bson:"getLastError,omitempty"`
	W        interface{} `bson:"w,omitempty"`
	WTimeout int         `bson:"wtimeout,omitempty"`
	FSync    bool        `bson:"fsync,omitempty"`
	J        bool        `bson:"j,omitempty"`
}
type Iter struct {
	m              sync.Mutex
	gotReply       sync.Cond
	session        *Session
	server         *mongoServer
	docData        queue
	err            error
	op             getMoreOp
	prefetch       float64
	docsToReceive  int
	docsBeforeMore int
	timeout        time.Duration
	limit          int32
	timedout       bool
	isFindCmd      bool
	isChangeStream bool
	maxTimeMS      int64
}
var (
	ErrNotFound = errors.New("not found")
	ErrCursor = errors.New("invalid cursor")
)
const (
	defaultPrefetch  = 0.25
	maxUpsertRetries = 5
)
func Dial(url string) (*Session, error) {
	session, err := DialWithTimeout(url, 10*time.Second)
	if err == nil {
		session.SetSyncTimeout(1 * time.Minute)
		session.SetSocketTimeout(1 * time.Minute)
	}
	return session, err
}
func DialWithTimeout(url string, timeout time.Duration) (*Session, error) {
	info, err := ParseURL(url)
	if err != nil {
		return nil, err
	}
	info.Timeout = timeout
	return DialWithInfo(info)
}
func ParseURL(url string) (*DialInfo, error) {
	uinfo, err := extractURL(url)
	if err != nil {
		return nil, err
	}
	ssl := false
	direct := false
	mechanism := ""
	service := ""
	source := ""
	setName := ""
	poolLimit := 0
	appName := ""
	readPreferenceMode := Primary
	var readPreferenceTagSets []bson.D
	minPoolSize := 0
	maxIdleTimeMS := 0
	safe := Safe{}
	for _, opt := range uinfo.options {
		switch opt.key {
		case "ssl":
			if v, err := strconv.ParseBool(opt.value); err == nil && v {
				ssl = true
			}
		case "authSource":
			source = opt.value
		case "authMechanism":
			mechanism = opt.value
		case "gssapiServiceName":
			service = opt.value
		case "replicaSet":
			setName = opt.value
		case "w":
			safe.WMode = opt.value
		case "j":
			journal, err := strconv.ParseBool(opt.value)
			if err != nil {
				return nil, errors.New("bad value for j: " + opt.value)
			}
			safe.J = journal
		case "wtimeoutMS":
			timeout, err := strconv.Atoi(opt.value)
			if err != nil {
				return nil, errors.New("bad value for wtimeoutMS: " + opt.value)
			}
			if timeout < 0 {
				return nil, errors.New("bad value (negative) for wtimeoutMS: " + opt.value)
			}
			safe.WTimeout = timeout
		case "maxPoolSize":
			poolLimit, err = strconv.Atoi(opt.value)
			if err != nil {
				return nil, errors.New("bad value for maxPoolSize: " + opt.value)
			}
		case "appName":
			if len(opt.value) > 128 {
				return nil, errors.New("appName too long, must be < 128 bytes: " + opt.value)
			}
			appName = opt.value
		case "readPreference":
			switch opt.value {
			case "nearest":
				readPreferenceMode = Nearest
			case "primary":
				readPreferenceMode = Primary
			case "primaryPreferred":
				readPreferenceMode = PrimaryPreferred
			case "secondary":
				readPreferenceMode = Secondary
			case "secondaryPreferred":
				readPreferenceMode = SecondaryPreferred
			default:
				return nil, errors.New("bad value for readPreference: " + opt.value)
			}
		case "readPreferenceTags":
			tags := strings.Split(opt.value, ",")
			var doc bson.D
			for _, tag := range tags {
				kvp := strings.Split(tag, ":")
				if len(kvp) != 2 {
					return nil, errors.New("bad value for readPreferenceTags: " + opt.value)
				}
				doc = append(doc, bson.DocElem{Name: strings.TrimSpace(kvp[0]), Value: strings.TrimSpace(kvp[1])})
			}
			readPreferenceTagSets = append(readPreferenceTagSets, doc)
		case "minPoolSize":
			minPoolSize, err = strconv.Atoi(opt.value)
			if err != nil {
				return nil, errors.New("bad value for minPoolSize: " + opt.value)
			}
			if minPoolSize < 0 {
				return nil, errors.New("bad value (negative) for minPoolSize: " + opt.value)
			}
		case "maxIdleTimeMS":
			maxIdleTimeMS, err = strconv.Atoi(opt.value)
			if err != nil {
				return nil, errors.New("bad value for maxIdleTimeMS: " + opt.value)
			}
			if maxIdleTimeMS < 0 {
				return nil, errors.New("bad value (negative) for maxIdleTimeMS: " + opt.value)
			}
		case "connect":
			if opt.value == "direct" {
				direct = true
				break
			}
			if opt.value == "replicaSet" {
				break
			}
			fallthrough
		default:
			return nil, errors.New("unsupported connection URL option: " + opt.key + "=" + opt.value)
		}
	}
	if readPreferenceMode == Primary && len(readPreferenceTagSets) > 0 {
		return nil, errors.New("readPreferenceTagSet may not be specified when readPreference is primary")
	}
	info := DialInfo{
		Addrs:     uinfo.addrs,
		Direct:    direct,
		Database:  uinfo.db,
		Username:  uinfo.user,
		Password:  uinfo.pass,
		Mechanism: mechanism,
		Service:   service,
		Source:    source,
		PoolLimit: poolLimit,
		AppName:   appName,
		ReadPreference: &ReadPreference{
			Mode:    readPreferenceMode,
			TagSets: readPreferenceTagSets,
		},
		Safe:           safe,
		ReplicaSetName: setName,
		MinPoolSize:    minPoolSize,
		MaxIdleTimeMS:  maxIdleTimeMS,
	}
	if ssl && info.DialServer == nil {
		info.DialServer = func(addr *ServerAddr) (net.Conn, error) {
			conn, err := tls.Dial("tcp", addr.String(), &tls.Config{})
			return conn, err
		}
	}
	return &info, nil
}
type DialInfo struct {
	Addrs []string
	Timeout time.Duration
	Database string
	ReplicaSetName string
	Source string
	Service string
	ServiceHost string
	Mechanism string
	Username string
	Password string
	PoolLimit int
	PoolTimeout time.Duration
	ReadTimeout time.Duration
	WriteTimeout time.Duration
	AppName string
	ReadPreference *ReadPreference
	Safe Safe
	FailFast bool
	Direct bool
	MinPoolSize int
	MaxIdleTimeMS int
	DialServer func(addr *ServerAddr) (net.Conn, error)
	Dial func(addr net.Addr) (net.Conn, error)
}
func (i *DialInfo) Copy() *DialInfo {
	var readPreference *ReadPreference
	if i.ReadPreference != nil {
		readPreference = &ReadPreference{
			Mode: i.ReadPreference.Mode,
		}
		readPreference.TagSets = make([]bson.D, len(i.ReadPreference.TagSets))
		copy(readPreference.TagSets, i.ReadPreference.TagSets)
	}
	info := &DialInfo{
		Timeout:        i.Timeout,
		Database:       i.Database,
		ReplicaSetName: i.ReplicaSetName,
		Source:         i.Source,
		Service:        i.Service,
		ServiceHost:    i.ServiceHost,
		Mechanism:      i.Mechanism,
		Username:       i.Username,
		Password:       i.Password,
		PoolLimit:      i.PoolLimit,
		PoolTimeout:    i.PoolTimeout,
		ReadTimeout:    i.ReadTimeout,
		WriteTimeout:   i.WriteTimeout,
		AppName:        i.AppName,
		ReadPreference: readPreference,
		FailFast:       i.FailFast,
		Direct:         i.Direct,
		MinPoolSize:    i.MinPoolSize,
		MaxIdleTimeMS:  i.MaxIdleTimeMS,
		DialServer:     i.DialServer,
		Dial:           i.Dial,
	}
	info.Addrs = make([]string, len(i.Addrs))
	copy(info.Addrs, i.Addrs)
	return info
}
func (i *DialInfo) readTimeout() time.Duration {
	if i.ReadTimeout == zeroDuration {
		return i.Timeout
	}
	return i.ReadTimeout
}
func (i *DialInfo) writeTimeout() time.Duration {
	if i.WriteTimeout == zeroDuration {
		return i.Timeout
	}
	return i.WriteTimeout
}
func (i *DialInfo) roundTripTimeout() time.Duration {
	return i.readTimeout() + i.writeTimeout()
}