diff options
| author | Kevin Lyda <kevin@ie.suberic.net> | 2017-01-27 09:08:58 +0000 | 
|---|---|---|
| committer | Niall Sheridan <nsheridan@gmail.com> | 2017-01-27 09:08:58 +0000 | 
| commit | 10dfd24117094ed81197c764af25cafe12a25dfd (patch) | |
| tree | 4af4c066daffb42469ed8a0e14d510dea321375b | |
| parent | 13054312850d1014e814d2f64afa030a4fea5ef3 (diff) | |
Remove mongo support
Resolves #40 
50 files changed, 7 insertions, 17248 deletions
diff --git a/.travis.yml b/.travis.yml index d36d907..fecbd37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@  language: go  services:    - mysql -  - mongodb  env: -  - MYSQL_TEST="true" MONGO_TEST="true" +  - MYSQL_TEST="true"  go:    - 1.7.5 @@ -22,7 +21,6 @@ install:  before_script:    - mysql < db/seed.sql -  - mongo db/seed.js  sudo: false  script: @@ -119,8 +119,8 @@ Exception to this: the `http_logfile` option **ONLY** writes to local files.  The database is used to record issued certificates for audit and revocation purposes. -- `type` : string. One of `mongo`, `mysql`, `sqlite` or `mem`. Default: `mem`. -- `address` : string. (`mongo` and `mysql` only) Hostname and optional port of the database server. For MongoDB replica sets separate multiple entries with commas. +- `type` : string. One of `mysql`, `sqlite` or `mem`. Default: `mem`. +- `address` : string. (`mysql` only) Hostname and optional port of the database server.  - `username` : string. Database username.  - `password` : string. Database password. This can be a secret stored in a [vault](https://www.vaultproject.io/) using the form `/vault/path/key` e.g. `/vault/secret/cashier/mysql_password`.  - `filename` : string. (`sqlite` only). Path to sqlite database. @@ -136,13 +136,6 @@ server {    }    database { -    type = "mongo" -    address = "mongo-host1.corp:27017,mongo-host2.corp:27018" -    username = "user" -    password = "passwd" -  } - -  database {      type = "mem"    } @@ -153,8 +146,8 @@ server {  }  ``` -Prior to using MySQL, MongoDB or SQLite you need to create the database and tables using [one of the provided files](db).   -e.g. `mysql < db/seed.sql` or `mongo db/seed.js`.   +Prior to using MySQL or SQLite you need to create the database and tables using [one of the provided files](db).   +e.g. `mysql < db/seed.sql`.    Obviously you should setup a role user for running in prodution.  ### datastore @@ -163,11 +156,10 @@ Obviously you should setup a role user for running in prodution.  ~~Datastores contain a record of issued certificates for audit and revocation purposes. The connection string is of the form `engine:username:password:host[:port]`.~~ -~~Supported database providers: `mysql`, `mongo`, `sqlite` and `mem`.~~ +~~Supported database providers: `mysql`, `sqlite` and `mem`.~~  ~~`mem` is an in-memory database intended for testing and takes no additional config options.~~    ~~`mysql` is the MySQL database and accepts `username`, `password` and `host` arguments. Only `username` and `host` arguments are required. `port` is assumed to be 3306 unless otherwise specified.~~   -~~`mongo` is MongoDB and accepts `username`, `password` and `host` arguments. All arguments are optional and multiple hosts can be specified using comma-separated values: `mongo:dbuser:dbpasswd:host1,host2`.~~    ~~`sqlite` is the SQLite database and accepts a `path` argument.~~  ~~If no datastore is specified the `mem` store is used by default.~~ @@ -179,8 +171,6 @@ server {    datastore = "mem"  # use the in-memory database.    datastore = "mysql:root::localhost"  # mysql running on localhost with the user 'root' and no password.    datastore = "mysql:cashier:PaSsWoRd:mydbprovider.example.com:5150"  # mysql running on a remote host on port 5150 -  datastore = "mongo:cashier:PaSsWoRd:mydbprovider.example.com:27018"  # mongo running on a remote host on port 27018 -  datastore = "mongo:cashier:PaSsWoRd:server1.example.com:27018,server2.example.com:27018"  # mongo running on multiple servers on port 27018    datastore = "sqlite:/data/certs.db"  }  ``` diff --git a/db/seed.js b/db/seed.js deleted file mode 100644 index c9d62fa..0000000 --- a/db/seed.js +++ /dev/null @@ -1,3 +0,0 @@ -conn = new Mongo(); -db = conn.getDB("certs"); -db.issued_certs.createIndex({"keyid": 1}, {unique: true}); diff --git a/server/config/config.go b/server/config/config.go index 9ac4a7d..573ae85 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -95,7 +95,7 @@ func convertDatastoreConfig(c *Config) {  		conf := c.Server.Datastore  		engine := strings.Split(conf, ":")[0]  		switch engine { -		case "mysql", "mongo": +		case "mysql":  			s := strings.SplitN(conf, ":", 4)  			engine, user, passwd, addrs := s[0], s[1], s[2], s[3]  			c.Server.Database = map[string]string{ diff --git a/server/config/config_test.go b/server/config/config_test.go index 182436a..b3f356e 100644 --- a/server/config/config_test.go +++ b/server/config/config_test.go @@ -68,9 +68,6 @@ func TestDatastoreConversion(t *testing.T) {  			"mysql:user:passwd:localhost:3306", Database{"type": "mysql", "username": "user", "password": "passwd", "address": "localhost:3306"},  		},  		{ -			"mongo:::host1,host2", Database{"type": "mongo", "username": "", "password": "", "address": "host1,host2"}, -		}, -		{  			"mem", Database{"type": "mem"},  		},  		{ diff --git a/server/store/mongo.go b/server/store/mongo.go deleted file mode 100644 index 6a23e89..0000000 --- a/server/store/mongo.go +++ /dev/null @@ -1,123 +0,0 @@ -package store - -import ( -	"strings" -	"time" - -	"github.com/nsheridan/cashier/server/config" - -	"golang.org/x/crypto/ssh" - -	mgo "gopkg.in/mgo.v2" -	"gopkg.in/mgo.v2/bson" -) - -var ( -	certsDB     = "certs" -	issuedTable = "issued_certs" -) - -func collection(session *mgo.Session) *mgo.Collection { -	return session.DB(certsDB).C(issuedTable) -} - -// NewMongoStore returns a MongoDB CertStorer. -func NewMongoStore(c config.Database) (*MongoStore, error) { -	m := &mgo.DialInfo{ -		Addrs:    strings.Split(c["address"], ","), -		Username: c["username"], -		Password: c["password"], -		Database: certsDB, -		Timeout:  time.Second * 5, -	} -	session, err := mgo.DialWithInfo(m) -	if err != nil { -		return nil, err -	} -	return &MongoStore{ -		session: session, -	}, nil -} - -var _ CertStorer = (*MongoStore)(nil) - -// MongoStore is a MongoDB-based CertStorer -type MongoStore struct { -	session *mgo.Session -} - -// Get a single *CertRecord -func (m *MongoStore) Get(id string) (*CertRecord, error) { -	s := m.session.Copy() -	defer s.Close() -	if err := s.Ping(); err != nil { -		return nil, err -	} -	c := &CertRecord{} -	err := collection(s).Find(bson.M{"keyid": id}).One(c) -	return c, err -} - -// SetCert parses a *ssh.Certificate and records it -func (m *MongoStore) SetCert(cert *ssh.Certificate) error { -	r := parseCertificate(cert) -	return m.SetRecord(r) -} - -// SetRecord records a *CertRecord -func (m *MongoStore) SetRecord(record *CertRecord) error { -	s := m.session.Copy() -	defer s.Close() -	if err := s.Ping(); err != nil { -		return err -	} -	return collection(s).Insert(record) -} - -// List returns all recorded certs. -// By default only active certs are returned. -func (m *MongoStore) List(includeExpired bool) ([]*CertRecord, error) { -	s := m.session.Copy() -	defer s.Close() -	if err := s.Ping(); err != nil { -		return nil, err -	} -	var result []*CertRecord -	var err error -	c := collection(s) -	if includeExpired { -		err = c.Find(nil).All(&result) -	} else { -		err = c.Find(bson.M{"expires": bson.M{"$gte": time.Now().UTC()}}).All(&result) -	} -	return result, err -} - -// Revoke an issued cert by id. -func (m *MongoStore) Revoke(id string) error { -	s := m.session.Copy() -	defer s.Close() -	if err := s.Ping(); err != nil { -		return err -	} -	c := collection(s) -	return c.Update(bson.M{"keyid": id}, bson.M{"$set": bson.M{"revoked": true}}) -} - -// GetRevoked returns all revoked certs -func (m *MongoStore) GetRevoked() ([]*CertRecord, error) { -	s := m.session.Copy() -	defer s.Close() -	if err := s.Ping(); err != nil { -		return nil, err -	} -	var result []*CertRecord -	err := collection(s).Find(bson.M{"expires": bson.M{"$gte": time.Now().UTC()}, "revoked": true}).All(&result) -	return result, err -} - -// Close the connection to the database -func (m *MongoStore) Close() error { -	m.session.Close() -	return nil -} diff --git a/server/store/store.go b/server/store/store.go index 249489a..d157fd1 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -13,8 +13,6 @@ import (  // New returns a new configured database.  func New(c config.Database) (CertStorer, error) {  	switch c["type"] { -	case "mongo": -		return NewMongoStore(c)  	case "mysql", "sqlite":  		return NewSQLStore(c)  	case "mem": diff --git a/server/store/store_test.go b/server/store/store_test.go index 4196c37..47e0f74 100644 --- a/server/store/store_test.go +++ b/server/store/store_test.go @@ -111,18 +111,6 @@ func TestMySQLStore(t *testing.T) {  	testStore(t, db)  } -func TestMongoStore(t *testing.T) { -	t.Parallel() -	if os.Getenv("MONGO_TEST") == "" { -		t.Skip("No MONGO_TEST environment variable") -	} -	db, err := NewMongoStore(map[string]string{"type": "mongo"}) -	if err != nil { -		t.Error(err) -	} -	testStore(t, db) -} -  func TestSQLiteStore(t *testing.T) {  	t.Parallel()  	f, err := ioutil.TempFile("", "sqlite_test_db") diff --git a/vendor/gopkg.in/mgo.v2/LICENSE b/vendor/gopkg.in/mgo.v2/LICENSE deleted file mode 100644 index 770c767..0000000 --- a/vendor/gopkg.in/mgo.v2/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -mgo - MongoDB driver for Go - -Copyright (c) 2010-2013 - Gustavo Niemeyer <gustavo@niemeyer.net> - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met:  - -1. Redistributions of source code must retain the above copyright notice, this -   list of conditions and the following disclaimer.  -2. Redistributions in binary form must reproduce the above copyright notice, -   this list of conditions and the following disclaimer in the documentation -   and/or other materials provided with the distribution.  - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/mgo.v2/Makefile b/vendor/gopkg.in/mgo.v2/Makefile deleted file mode 100644 index d1027d4..0000000 --- a/vendor/gopkg.in/mgo.v2/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -startdb: -	@harness/setup.sh start - -stopdb: -	@harness/setup.sh stop diff --git a/vendor/gopkg.in/mgo.v2/README.md b/vendor/gopkg.in/mgo.v2/README.md deleted file mode 100644 index f4e452c..0000000 --- a/vendor/gopkg.in/mgo.v2/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The MongoDB driver for Go -------------------------- - -Please go to [http://labix.org/mgo](http://labix.org/mgo) for all project details. diff --git a/vendor/gopkg.in/mgo.v2/auth.go b/vendor/gopkg.in/mgo.v2/auth.go deleted file mode 100644 index dc26e52..0000000 --- a/vendor/gopkg.in/mgo.v2/auth.go +++ /dev/null @@ -1,467 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"crypto/md5" -	"crypto/sha1" -	"encoding/hex" -	"errors" -	"fmt" -	"sync" - -	"gopkg.in/mgo.v2/bson" -	"gopkg.in/mgo.v2/internal/scram" -) - -type authCmd struct { -	Authenticate int - -	Nonce string -	User  string -	Key   string -} - -type startSaslCmd struct { -	StartSASL int `bson:"startSasl"` -} - -type authResult struct { -	ErrMsg string -	Ok     bool -} - -type getNonceCmd struct { -	GetNonce int -} - -type getNonceResult struct { -	Nonce string -	Err   string "$err" -	Code  int -} - -type logoutCmd struct { -	Logout int -} - -type saslCmd struct { -	Start          int    `bson:"saslStart,omitempty"` -	Continue       int    `bson:"saslContinue,omitempty"` -	ConversationId int    `bson:"conversationId,omitempty"` -	Mechanism      string `bson:"mechanism,omitempty"` -	Payload        []byte -} - -type saslResult struct { -	Ok    bool `bson:"ok"` -	NotOk bool `bson:"code"` // Server <= 2.3.2 returns ok=1 & code>0 on errors (WTF?) -	Done  bool - -	ConversationId int `bson:"conversationId"` -	Payload        []byte -	ErrMsg         string -} - -type saslStepper interface { -	Step(serverData []byte) (clientData []byte, done bool, err error) -	Close() -} - -func (socket *mongoSocket) getNonce() (nonce string, err error) { -	socket.Lock() -	for socket.cachedNonce == "" && socket.dead == nil { -		debugf("Socket %p to %s: waiting for nonce", socket, socket.addr) -		socket.gotNonce.Wait() -	} -	if socket.cachedNonce == "mongos" { -		socket.Unlock() -		return "", errors.New("Can't authenticate with mongos; see http://j.mp/mongos-auth") -	} -	debugf("Socket %p to %s: got nonce", socket, socket.addr) -	nonce, err = socket.cachedNonce, socket.dead -	socket.cachedNonce = "" -	socket.Unlock() -	if err != nil { -		nonce = "" -	} -	return -} - -func (socket *mongoSocket) resetNonce() { -	debugf("Socket %p to %s: requesting a new nonce", socket, socket.addr) -	op := &queryOp{} -	op.query = &getNonceCmd{GetNonce: 1} -	op.collection = "admin.$cmd" -	op.limit = -1 -	op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { -		if err != nil { -			socket.kill(errors.New("getNonce: "+err.Error()), true) -			return -		} -		result := &getNonceResult{} -		err = bson.Unmarshal(docData, &result) -		if err != nil { -			socket.kill(errors.New("Failed to unmarshal nonce: "+err.Error()), true) -			return -		} -		debugf("Socket %p to %s: nonce unmarshalled: %#v", socket, socket.addr, result) -		if result.Code == 13390 { -			// mongos doesn't yet support auth (see http://j.mp/mongos-auth) -			result.Nonce = "mongos" -		} else if result.Nonce == "" { -			var msg string -			if result.Err != "" { -				msg = fmt.Sprintf("Got an empty nonce: %s (%d)", result.Err, result.Code) -			} else { -				msg = "Got an empty nonce" -			} -			socket.kill(errors.New(msg), true) -			return -		} -		socket.Lock() -		if socket.cachedNonce != "" { -			socket.Unlock() -			panic("resetNonce: nonce already cached") -		} -		socket.cachedNonce = result.Nonce -		socket.gotNonce.Signal() -		socket.Unlock() -	} -	err := socket.Query(op) -	if err != nil { -		socket.kill(errors.New("resetNonce: "+err.Error()), true) -	} -} - -func (socket *mongoSocket) Login(cred Credential) error { -	socket.Lock() -	if cred.Mechanism == "" && socket.serverInfo.MaxWireVersion >= 3 { -		cred.Mechanism = "SCRAM-SHA-1" -	} -	for _, sockCred := range socket.creds { -		if sockCred == cred { -			debugf("Socket %p to %s: login: db=%q user=%q (already logged in)", socket, socket.addr, cred.Source, cred.Username) -			socket.Unlock() -			return nil -		} -	} -	if socket.dropLogout(cred) { -		debugf("Socket %p to %s: login: db=%q user=%q (cached)", socket, socket.addr, cred.Source, cred.Username) -		socket.creds = append(socket.creds, cred) -		socket.Unlock() -		return nil -	} -	socket.Unlock() - -	debugf("Socket %p to %s: login: db=%q user=%q", socket, socket.addr, cred.Source, cred.Username) - -	var err error -	switch cred.Mechanism { -	case "", "MONGODB-CR", "MONGO-CR": // Name changed to MONGODB-CR in SERVER-8501. -		err = socket.loginClassic(cred) -	case "PLAIN": -		err = socket.loginPlain(cred) -	case "MONGODB-X509": -		err = socket.loginX509(cred) -	default: -		// Try SASL for everything else, if it is available. -		err = socket.loginSASL(cred) -	} - -	if err != nil { -		debugf("Socket %p to %s: login error: %s", socket, socket.addr, err) -	} else { -		debugf("Socket %p to %s: login successful", socket, socket.addr) -	} -	return err -} - -func (socket *mongoSocket) loginClassic(cred Credential) error { -	// Note that this only works properly because this function is -	// synchronous, which means the nonce won't get reset while we're -	// using it and any other login requests will block waiting for a -	// new nonce provided in the defer call below. -	nonce, err := socket.getNonce() -	if err != nil { -		return err -	} -	defer socket.resetNonce() - -	psum := md5.New() -	psum.Write([]byte(cred.Username + ":mongo:" + cred.Password)) - -	ksum := md5.New() -	ksum.Write([]byte(nonce + cred.Username)) -	ksum.Write([]byte(hex.EncodeToString(psum.Sum(nil)))) - -	key := hex.EncodeToString(ksum.Sum(nil)) - -	cmd := authCmd{Authenticate: 1, User: cred.Username, Nonce: nonce, Key: key} -	res := authResult{} -	return socket.loginRun(cred.Source, &cmd, &res, func() error { -		if !res.Ok { -			return errors.New(res.ErrMsg) -		} -		socket.Lock() -		socket.dropAuth(cred.Source) -		socket.creds = append(socket.creds, cred) -		socket.Unlock() -		return nil -	}) -} - -type authX509Cmd struct { -	Authenticate int -	User         string -	Mechanism    string -} - -func (socket *mongoSocket) loginX509(cred Credential) error { -	cmd := authX509Cmd{Authenticate: 1, User: cred.Username, Mechanism: "MONGODB-X509"} -	res := authResult{} -	return socket.loginRun(cred.Source, &cmd, &res, func() error { -		if !res.Ok { -			return errors.New(res.ErrMsg) -		} -		socket.Lock() -		socket.dropAuth(cred.Source) -		socket.creds = append(socket.creds, cred) -		socket.Unlock() -		return nil -	}) -} - -func (socket *mongoSocket) loginPlain(cred Credential) error { -	cmd := saslCmd{Start: 1, Mechanism: "PLAIN", Payload: []byte("\x00" + cred.Username + "\x00" + cred.Password)} -	res := authResult{} -	return socket.loginRun(cred.Source, &cmd, &res, func() error { -		if !res.Ok { -			return errors.New(res.ErrMsg) -		} -		socket.Lock() -		socket.dropAuth(cred.Source) -		socket.creds = append(socket.creds, cred) -		socket.Unlock() -		return nil -	}) -} - -func (socket *mongoSocket) loginSASL(cred Credential) error { -	var sasl saslStepper -	var err error -	if cred.Mechanism == "SCRAM-SHA-1" { -		// SCRAM is handled without external libraries. -		sasl = saslNewScram(cred) -	} else if len(cred.ServiceHost) > 0 { -		sasl, err = saslNew(cred, cred.ServiceHost) -	} else { -		sasl, err = saslNew(cred, socket.Server().Addr) -	} -	if err != nil { -		return err -	} -	defer sasl.Close() - -	// The goal of this logic is to carry a locked socket until the -	// local SASL step confirms the auth is valid; the socket needs to be -	// locked so that concurrent action doesn't leave the socket in an -	// auth state that doesn't reflect the operations that took place. -	// As a simple case, imagine inverting login=>logout to logout=>login. -	// -	// The logic below works because the lock func isn't called concurrently. -	locked := false -	lock := func(b bool) { -		if locked != b { -			locked = b -			if b { -				socket.Lock() -			} else { -				socket.Unlock() -			} -		} -	} - -	lock(true) -	defer lock(false) - -	start := 1 -	cmd := saslCmd{} -	res := saslResult{} -	for { -		payload, done, err := sasl.Step(res.Payload) -		if err != nil { -			return err -		} -		if done && res.Done { -			socket.dropAuth(cred.Source) -			socket.creds = append(socket.creds, cred) -			break -		} -		lock(false) - -		cmd = saslCmd{ -			Start:          start, -			Continue:       1 - start, -			ConversationId: res.ConversationId, -			Mechanism:      cred.Mechanism, -			Payload:        payload, -		} -		start = 0 -		err = socket.loginRun(cred.Source, &cmd, &res, func() error { -			// See the comment on lock for why this is necessary. -			lock(true) -			if !res.Ok || res.NotOk { -				return fmt.Errorf("server returned error on SASL authentication step: %s", res.ErrMsg) -			} -			return nil -		}) -		if err != nil { -			return err -		} -		if done && res.Done { -			socket.dropAuth(cred.Source) -			socket.creds = append(socket.creds, cred) -			break -		} -	} - -	return nil -} - -func saslNewScram(cred Credential) *saslScram { -	credsum := md5.New() -	credsum.Write([]byte(cred.Username + ":mongo:" + cred.Password)) -	client := scram.NewClient(sha1.New, cred.Username, hex.EncodeToString(credsum.Sum(nil))) -	return &saslScram{cred: cred, client: client} -} - -type saslScram struct { -	cred   Credential -	client *scram.Client -} - -func (s *saslScram) Close() {} - -func (s *saslScram) Step(serverData []byte) (clientData []byte, done bool, err error) { -	more := s.client.Step(serverData) -	return s.client.Out(), !more, s.client.Err() -} - -func (socket *mongoSocket) loginRun(db string, query, result interface{}, f func() error) error { -	var mutex sync.Mutex -	var replyErr error -	mutex.Lock() - -	op := queryOp{} -	op.query = query -	op.collection = db + ".$cmd" -	op.limit = -1 -	op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { -		defer mutex.Unlock() - -		if err != nil { -			replyErr = err -			return -		} - -		err = bson.Unmarshal(docData, result) -		if err != nil { -			replyErr = err -		} else { -			// Must handle this within the read loop for the socket, so -			// that concurrent login requests are properly ordered. -			replyErr = f() -		} -	} - -	err := socket.Query(&op) -	if err != nil { -		return err -	} -	mutex.Lock() // Wait. -	return replyErr -} - -func (socket *mongoSocket) Logout(db string) { -	socket.Lock() -	cred, found := socket.dropAuth(db) -	if found { -		debugf("Socket %p to %s: logout: db=%q (flagged)", socket, socket.addr, db) -		socket.logout = append(socket.logout, cred) -	} -	socket.Unlock() -} - -func (socket *mongoSocket) LogoutAll() { -	socket.Lock() -	if l := len(socket.creds); l > 0 { -		debugf("Socket %p to %s: logout all (flagged %d)", socket, socket.addr, l) -		socket.logout = append(socket.logout, socket.creds...) -		socket.creds = socket.creds[0:0] -	} -	socket.Unlock() -} - -func (socket *mongoSocket) flushLogout() (ops []interface{}) { -	socket.Lock() -	if l := len(socket.logout); l > 0 { -		debugf("Socket %p to %s: logout all (flushing %d)", socket, socket.addr, l) -		for i := 0; i != l; i++ { -			op := queryOp{} -			op.query = &logoutCmd{1} -			op.collection = socket.logout[i].Source + ".$cmd" -			op.limit = -1 -			ops = append(ops, &op) -		} -		socket.logout = socket.logout[0:0] -	} -	socket.Unlock() -	return -} - -func (socket *mongoSocket) dropAuth(db string) (cred Credential, found bool) { -	for i, sockCred := range socket.creds { -		if sockCred.Source == db { -			copy(socket.creds[i:], socket.creds[i+1:]) -			socket.creds = socket.creds[:len(socket.creds)-1] -			return sockCred, true -		} -	} -	return cred, false -} - -func (socket *mongoSocket) dropLogout(cred Credential) (found bool) { -	for i, sockCred := range socket.logout { -		if sockCred == cred { -			copy(socket.logout[i:], socket.logout[i+1:]) -			socket.logout = socket.logout[:len(socket.logout)-1] -			return true -		} -	} -	return false -} diff --git a/vendor/gopkg.in/mgo.v2/bson/LICENSE b/vendor/gopkg.in/mgo.v2/bson/LICENSE deleted file mode 100644 index 8903260..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -BSON library for Go - -Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met:  - -1. Redistributions of source code must retain the above copyright notice, this -   list of conditions and the following disclaimer.  -2. Redistributions in binary form must reproduce the above copyright notice, -   this list of conditions and the following disclaimer in the documentation -   and/or other materials provided with the distribution.  - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/mgo.v2/bson/bson.go b/vendor/gopkg.in/mgo.v2/bson/bson.go deleted file mode 100644 index 7fb7f8c..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/bson.go +++ /dev/null @@ -1,738 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Package bson is an implementation of the BSON specification for Go: -// -//     http://bsonspec.org -// -// It was created as part of the mgo MongoDB driver for Go, but is standalone -// and may be used on its own without the driver. -package bson - -import ( -	"bytes" -	"crypto/md5" -	"crypto/rand" -	"encoding/binary" -	"encoding/hex" -	"encoding/json" -	"errors" -	"fmt" -	"io" -	"os" -	"reflect" -	"runtime" -	"strings" -	"sync" -	"sync/atomic" -	"time" -) - -// -------------------------------------------------------------------------- -// The public API. - -// A value implementing the bson.Getter interface will have its GetBSON -// method called when the given value has to be marshalled, and the result -// of this method will be marshaled in place of the actual object. -// -// If GetBSON returns return a non-nil error, the marshalling procedure -// will stop and error out with the provided value. -type Getter interface { -	GetBSON() (interface{}, error) -} - -// A value implementing the bson.Setter interface will receive the BSON -// value via the SetBSON method during unmarshaling, and the object -// itself will not be changed as usual. -// -// If setting the value works, the method should return nil or alternatively -// bson.SetZero to set the respective field to its zero value (nil for -// pointer types). If SetBSON returns a value of type bson.TypeError, the -// BSON value will be omitted from a map or slice being decoded and the -// unmarshalling will continue. If it returns any other non-nil error, the -// unmarshalling procedure will stop and error out with the provided value. -// -// This interface is generally useful in pointer receivers, since the method -// will want to change the receiver. A type field that implements the Setter -// interface doesn't have to be a pointer, though. -// -// Unlike the usual behavior, unmarshalling onto a value that implements a -// Setter interface will NOT reset the value to its zero state. This allows -// the value to decide by itself how to be unmarshalled. -// -// For example: -// -//     type MyString string -// -//     func (s *MyString) SetBSON(raw bson.Raw) error { -//         return raw.Unmarshal(s) -//     } -// -type Setter interface { -	SetBSON(raw Raw) error -} - -// SetZero may be returned from a SetBSON method to have the value set to -// its respective zero value. When used in pointer values, this will set the -// field to nil rather than to the pre-allocated value. -var SetZero = errors.New("set to zero") - -// M is a convenient alias for a map[string]interface{} map, useful for -// dealing with BSON in a native way.  For instance: -// -//     bson.M{"a": 1, "b": true} -// -// There's no special handling for this type in addition to what's done anyway -// for an equivalent map type.  Elements in the map will be dumped in an -// undefined ordered. See also the bson.D type for an ordered alternative. -type M map[string]interface{} - -// D represents a BSON document containing ordered elements. For example: -// -//     bson.D{{"a", 1}, {"b", true}} -// -// In some situations, such as when creating indexes for MongoDB, the order in -// which the elements are defined is important.  If the order is not important, -// using a map is generally more comfortable. See bson.M and bson.RawD. -type D []DocElem - -// DocElem is an element of the bson.D document representation. -type DocElem struct { -	Name  string -	Value interface{} -} - -// Map returns a map out of the ordered element name/value pairs in d. -func (d D) Map() (m M) { -	m = make(M, len(d)) -	for _, item := range d { -		m[item.Name] = item.Value -	} -	return m -} - -// The Raw type represents raw unprocessed BSON documents and elements. -// Kind is the kind of element as defined per the BSON specification, and -// Data is the raw unprocessed data for the respective element. -// Using this type it is possible to unmarshal or marshal values partially. -// -// Relevant documentation: -// -//     http://bsonspec.org/#/specification -// -type Raw struct { -	Kind byte -	Data []byte -} - -// RawD represents a BSON document containing raw unprocessed elements. -// This low-level representation may be useful when lazily processing -// documents of uncertain content, or when manipulating the raw content -// documents in general. -type RawD []RawDocElem - -// See the RawD type. -type RawDocElem struct { -	Name  string -	Value Raw -} - -// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes -// long. MongoDB objects by default have such a property set in their "_id" -// property. -// -// http://www.mongodb.org/display/DOCS/Object+IDs -type ObjectId string - -// ObjectIdHex returns an ObjectId from the provided hex representation. -// Calling this function with an invalid hex representation will -// cause a runtime panic. See the IsObjectIdHex function. -func ObjectIdHex(s string) ObjectId { -	d, err := hex.DecodeString(s) -	if err != nil || len(d) != 12 { -		panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s)) -	} -	return ObjectId(d) -} - -// IsObjectIdHex returns whether s is a valid hex representation of -// an ObjectId. See the ObjectIdHex function. -func IsObjectIdHex(s string) bool { -	if len(s) != 24 { -		return false -	} -	_, err := hex.DecodeString(s) -	return err == nil -} - -// objectIdCounter is atomically incremented when generating a new ObjectId -// using NewObjectId() function. It's used as a counter part of an id. -var objectIdCounter uint32 = readRandomUint32() - -// readRandomUint32 returns a random objectIdCounter. -func readRandomUint32() uint32 { -	var b [4]byte -	_, err := io.ReadFull(rand.Reader, b[:]) -	if err != nil { -		panic(fmt.Errorf("cannot read random object id: %v", err)) -	} -	return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)) -} - -// machineId stores machine id generated once and used in subsequent calls -// to NewObjectId function. -var machineId = readMachineId() -var processId = os.Getpid() - -// readMachineId generates and returns a machine id. -// If this function fails to get the hostname it will cause a runtime error. -func readMachineId() []byte { -	var sum [3]byte -	id := sum[:] -	hostname, err1 := os.Hostname() -	if err1 != nil { -		_, err2 := io.ReadFull(rand.Reader, id) -		if err2 != nil { -			panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) -		} -		return id -	} -	hw := md5.New() -	hw.Write([]byte(hostname)) -	copy(id, hw.Sum(nil)) -	return id -} - -// NewObjectId returns a new unique ObjectId. -func NewObjectId() ObjectId { -	var b [12]byte -	// Timestamp, 4 bytes, big endian -	binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) -	// Machine, first 3 bytes of md5(hostname) -	b[4] = machineId[0] -	b[5] = machineId[1] -	b[6] = machineId[2] -	// Pid, 2 bytes, specs don't specify endianness, but we use big endian. -	b[7] = byte(processId >> 8) -	b[8] = byte(processId) -	// Increment, 3 bytes, big endian -	i := atomic.AddUint32(&objectIdCounter, 1) -	b[9] = byte(i >> 16) -	b[10] = byte(i >> 8) -	b[11] = byte(i) -	return ObjectId(b[:]) -} - -// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled -// with the provided number of seconds from epoch UTC, and all other parts -// filled with zeroes. It's not safe to insert a document with an id generated -// by this method, it is useful only for queries to find documents with ids -// generated before or after the specified timestamp. -func NewObjectIdWithTime(t time.Time) ObjectId { -	var b [12]byte -	binary.BigEndian.PutUint32(b[:4], uint32(t.Unix())) -	return ObjectId(string(b[:])) -} - -// String returns a hex string representation of the id. -// Example: ObjectIdHex("4d88e15b60f486e428412dc9"). -func (id ObjectId) String() string { -	return fmt.Sprintf(`ObjectIdHex("%x")`, string(id)) -} - -// Hex returns a hex representation of the ObjectId. -func (id ObjectId) Hex() string { -	return hex.EncodeToString([]byte(id)) -} - -// MarshalJSON turns a bson.ObjectId into a json.Marshaller. -func (id ObjectId) MarshalJSON() ([]byte, error) { -	return []byte(fmt.Sprintf(`"%x"`, string(id))), nil -} - -var nullBytes = []byte("null") - -// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller. -func (id *ObjectId) UnmarshalJSON(data []byte) error { -	if len(data) > 0 && (data[0] == '{' || data[0] == 'O') { -		var v struct { -			Id json.RawMessage `json:"$oid"` -			Func struct { -				Id json.RawMessage -			} `json:"$oidFunc"` -		} -		err := jdec(data, &v) -		if err == nil { -			if len(v.Id) > 0 { -				data = []byte(v.Id) -			} else { -				data = []byte(v.Func.Id) -			} -		} -	} -	if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) { -		*id = "" -		return nil -	} -	if len(data) != 26 || data[0] != '"' || data[25] != '"' { -		return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s", string(data))) -	} -	var buf [12]byte -	_, err := hex.Decode(buf[:], data[1:25]) -	if err != nil { -		return errors.New(fmt.Sprintf("invalid ObjectId in JSON: %s (%s)", string(data), err)) -	} -	*id = ObjectId(string(buf[:])) -	return nil -} - -// MarshalText turns bson.ObjectId into an encoding.TextMarshaler. -func (id ObjectId) MarshalText() ([]byte, error) { -	return []byte(fmt.Sprintf("%x", string(id))), nil -} - -// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler. -func (id *ObjectId) UnmarshalText(data []byte) error { -	if len(data) == 1 && data[0] == ' ' || len(data) == 0 { -		*id = "" -		return nil -	} -	if len(data) != 24 { -		return fmt.Errorf("invalid ObjectId: %s", data) -	} -	var buf [12]byte -	_, err := hex.Decode(buf[:], data[:]) -	if err != nil { -		return fmt.Errorf("invalid ObjectId: %s (%s)", data, err) -	} -	*id = ObjectId(string(buf[:])) -	return nil -} - -// Valid returns true if id is valid. A valid id must contain exactly 12 bytes. -func (id ObjectId) Valid() bool { -	return len(id) == 12 -} - -// byteSlice returns byte slice of id from start to end. -// Calling this function with an invalid id will cause a runtime panic. -func (id ObjectId) byteSlice(start, end int) []byte { -	if len(id) != 12 { -		panic(fmt.Sprintf("invalid ObjectId: %q", string(id))) -	} -	return []byte(string(id)[start:end]) -} - -// Time returns the timestamp part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Time() time.Time { -	// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch. -	secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4))) -	return time.Unix(secs, 0) -} - -// Machine returns the 3-byte machine id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Machine() []byte { -	return id.byteSlice(4, 7) -} - -// Pid returns the process id part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Pid() uint16 { -	return binary.BigEndian.Uint16(id.byteSlice(7, 9)) -} - -// Counter returns the incrementing value part of the id. -// It's a runtime error to call this method with an invalid id. -func (id ObjectId) Counter() int32 { -	b := id.byteSlice(9, 12) -	// Counter is stored as big-endian 3-byte value -	return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])) -} - -// The Symbol type is similar to a string and is used in languages with a -// distinct symbol type. -type Symbol string - -// Now returns the current time with millisecond precision. MongoDB stores -// timestamps with the same precision, so a Time returned from this method -// will not change after a roundtrip to the database. That's the only reason -// why this function exists. Using the time.Now function also works fine -// otherwise. -func Now() time.Time { -	return time.Unix(0, time.Now().UnixNano()/1e6*1e6) -} - -// MongoTimestamp is a special internal type used by MongoDB that for some -// strange reason has its own datatype defined in BSON. -type MongoTimestamp int64 - -type orderKey int64 - -// MaxKey is a special value that compares higher than all other possible BSON -// values in a MongoDB database. -var MaxKey = orderKey(1<<63 - 1) - -// MinKey is a special value that compares lower than all other possible BSON -// values in a MongoDB database. -var MinKey = orderKey(-1 << 63) - -type undefined struct{} - -// Undefined represents the undefined BSON value. -var Undefined undefined - -// Binary is a representation for non-standard binary values.  Any kind should -// work, but the following are known as of this writing: -// -//   0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}. -//   0x01 - Function (!?) -//   0x02 - Obsolete generic. -//   0x03 - UUID -//   0x05 - MD5 -//   0x80 - User defined. -// -type Binary struct { -	Kind byte -	Data []byte -} - -// RegEx represents a regular expression.  The Options field may contain -// individual characters defining the way in which the pattern should be -// applied, and must be sorted. Valid options as of this writing are 'i' for -// case insensitive matching, 'm' for multi-line matching, 'x' for verbose -// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all -// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match -// unicode. The value of the Options parameter is not verified before being -// marshaled into the BSON format. -type RegEx struct { -	Pattern string -	Options string -} - -// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it -// will be marshaled as a mapping from identifiers to values that may be -// used when evaluating the provided Code. -type JavaScript struct { -	Code  string -	Scope interface{} -} - -// DBPointer refers to a document id in a namespace. -// -// This type is deprecated in the BSON specification and should not be used -// except for backwards compatibility with ancient applications. -type DBPointer struct { -	Namespace string -	Id        ObjectId -} - -const initialBufferSize = 64 - -func handleErr(err *error) { -	if r := recover(); r != nil { -		if _, ok := r.(runtime.Error); ok { -			panic(r) -		} else if _, ok := r.(externalPanic); ok { -			panic(r) -		} else if s, ok := r.(string); ok { -			*err = errors.New(s) -		} else if e, ok := r.(error); ok { -			*err = e -		} else { -			panic(r) -		} -	} -} - -// Marshal serializes the in value, which may be a map or a struct value. -// In the case of struct values, only exported fields will be serialized, -// and the order of serialized fields will match that of the struct itself. -// The lowercased field name is used as the key for each exported field, -// but this behavior may be changed using the respective field tag. -// The tag may also contain flags to tweak the marshalling behavior for -// the field. The tag formats accepted are: -// -//     "[<key>][,<flag1>[,<flag2>]]" -// -//     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` -// -// The following flags are currently supported: -// -//     omitempty  Only include the field if it's not set to the zero -//                value for the type or to empty slices or maps. -// -//     minsize    Marshal an int64 value as an int32, if that's feasible -//                while preserving the numeric value. -// -//     inline     Inline the field, which must be a struct or a map, -//                causing all of its fields or keys to be processed as if -//                they were part of the outer struct. For maps, keys must -//                not conflict with the bson keys of other struct fields. -// -// Some examples: -// -//     type T struct { -//         A bool -//         B int    "myb" -//         C string "myc,omitempty" -//         D string `bson:",omitempty" json:"jsonkey"` -//         E int64  ",minsize" -//         F int64  "myf,omitempty,minsize" -//     } -// -func Marshal(in interface{}) (out []byte, err error) { -	defer handleErr(&err) -	e := &encoder{make([]byte, 0, initialBufferSize)} -	e.addDoc(reflect.ValueOf(in)) -	return e.out, nil -} - -// Unmarshal deserializes data from in into the out value.  The out value -// must be a map, a pointer to a struct, or a pointer to a bson.D value. -// In the case of struct values, only exported fields will be deserialized. -// The lowercased field name is used as the key for each exported field, -// but this behavior may be changed using the respective field tag. -// The tag may also contain flags to tweak the marshalling behavior for -// the field. The tag formats accepted are: -// -//     "[<key>][,<flag1>[,<flag2>]]" -// -//     `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)` -// -// The following flags are currently supported during unmarshal (see the -// Marshal method for other flags): -// -//     inline     Inline the field, which must be a struct or a map. -//                Inlined structs are handled as if its fields were part -//                of the outer struct. An inlined map causes keys that do -//                not match any other struct field to be inserted in the -//                map rather than being discarded as usual. -// -// The target field or element types of out may not necessarily match -// the BSON values of the provided data.  The following conversions are -// made automatically: -// -// - Numeric types are converted if at least the integer part of the -//   value would be preserved correctly -// - Bools are converted to numeric types as 1 or 0 -// - Numeric types are converted to bools as true if not 0 or false otherwise -// - Binary and string BSON data is converted to a string, array or byte slice -// -// If the value would not fit the type and cannot be converted, it's -// silently skipped. -// -// Pointer values are initialized when necessary. -func Unmarshal(in []byte, out interface{}) (err error) { -	if raw, ok := out.(*Raw); ok { -		raw.Kind = 3 -		raw.Data = in -		return nil -	} -	defer handleErr(&err) -	v := reflect.ValueOf(out) -	switch v.Kind() { -	case reflect.Ptr: -		fallthrough -	case reflect.Map: -		d := newDecoder(in) -		d.readDocTo(v) -	case reflect.Struct: -		return errors.New("Unmarshal can't deal with struct values. Use a pointer.") -	default: -		return errors.New("Unmarshal needs a map or a pointer to a struct.") -	} -	return nil -} - -// Unmarshal deserializes raw into the out value.  If the out value type -// is not compatible with raw, a *bson.TypeError is returned. -// -// See the Unmarshal function documentation for more details on the -// unmarshalling process. -func (raw Raw) Unmarshal(out interface{}) (err error) { -	defer handleErr(&err) -	v := reflect.ValueOf(out) -	switch v.Kind() { -	case reflect.Ptr: -		v = v.Elem() -		fallthrough -	case reflect.Map: -		d := newDecoder(raw.Data) -		good := d.readElemTo(v, raw.Kind) -		if !good { -			return &TypeError{v.Type(), raw.Kind} -		} -	case reflect.Struct: -		return errors.New("Raw Unmarshal can't deal with struct values. Use a pointer.") -	default: -		return errors.New("Raw Unmarshal needs a map or a valid pointer.") -	} -	return nil -} - -type TypeError struct { -	Type reflect.Type -	Kind byte -} - -func (e *TypeError) Error() string { -	return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String()) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -type structInfo struct { -	FieldsMap  map[string]fieldInfo -	FieldsList []fieldInfo -	InlineMap  int -	Zero       reflect.Value -} - -type fieldInfo struct { -	Key       string -	Num       int -	OmitEmpty bool -	MinSize   bool -	Inline    []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var structMapMutex sync.RWMutex - -type externalPanic string - -func (e externalPanic) String() string { -	return string(e) -} - -func getStructInfo(st reflect.Type) (*structInfo, error) { -	structMapMutex.RLock() -	sinfo, found := structMap[st] -	structMapMutex.RUnlock() -	if found { -		return sinfo, nil -	} -	n := st.NumField() -	fieldsMap := make(map[string]fieldInfo) -	fieldsList := make([]fieldInfo, 0, n) -	inlineMap := -1 -	for i := 0; i != n; i++ { -		field := st.Field(i) -		if field.PkgPath != "" && !field.Anonymous { -			continue // Private field -		} - -		info := fieldInfo{Num: i} - -		tag := field.Tag.Get("bson") -		if tag == "" && strings.Index(string(field.Tag), ":") < 0 { -			tag = string(field.Tag) -		} -		if tag == "-" { -			continue -		} - -		inline := false -		fields := strings.Split(tag, ",") -		if len(fields) > 1 { -			for _, flag := range fields[1:] { -				switch flag { -				case "omitempty": -					info.OmitEmpty = true -				case "minsize": -					info.MinSize = true -				case "inline": -					inline = true -				default: -					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st) -					panic(externalPanic(msg)) -				} -			} -			tag = fields[0] -		} - -		if inline { -			switch field.Type.Kind() { -			case reflect.Map: -				if inlineMap >= 0 { -					return nil, errors.New("Multiple ,inline maps in struct " + st.String()) -				} -				if field.Type.Key() != reflect.TypeOf("") { -					return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) -				} -				inlineMap = info.Num -			case reflect.Struct: -				sinfo, err := getStructInfo(field.Type) -				if err != nil { -					return nil, err -				} -				for _, finfo := range sinfo.FieldsList { -					if _, found := fieldsMap[finfo.Key]; found { -						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() -						return nil, errors.New(msg) -					} -					if finfo.Inline == nil { -						finfo.Inline = []int{i, finfo.Num} -					} else { -						finfo.Inline = append([]int{i}, finfo.Inline...) -					} -					fieldsMap[finfo.Key] = finfo -					fieldsList = append(fieldsList, finfo) -				} -			default: -				panic("Option ,inline needs a struct value or map field") -			} -			continue -		} - -		if tag != "" { -			info.Key = tag -		} else { -			info.Key = strings.ToLower(field.Name) -		} - -		if _, found = fieldsMap[info.Key]; found { -			msg := "Duplicated key '" + info.Key + "' in struct " + st.String() -			return nil, errors.New(msg) -		} - -		fieldsList = append(fieldsList, info) -		fieldsMap[info.Key] = info -	} -	sinfo = &structInfo{ -		fieldsMap, -		fieldsList, -		inlineMap, -		reflect.New(st).Elem(), -	} -	structMapMutex.Lock() -	structMap[st] = sinfo -	structMapMutex.Unlock() -	return sinfo, nil -} diff --git a/vendor/gopkg.in/mgo.v2/bson/decimal.go b/vendor/gopkg.in/mgo.v2/bson/decimal.go deleted file mode 100644 index 3d2f700..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/decimal.go +++ /dev/null @@ -1,310 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package bson - -import ( -	"fmt" -	"strconv" -	"strings" -) - -// Decimal128 holds decimal128 BSON values. -type Decimal128 struct { -	h, l uint64 -} - -func (d Decimal128) String() string { -	var pos int     // positive sign -	var e int       // exponent -	var h, l uint64 // significand high/low - -	if d.h>>63&1 == 0 { -		pos = 1 -	} - -	switch d.h >> 58 & (1<<5 - 1) { -	case 0x1F: -		return "NaN" -	case 0x1E: -		return "-Inf"[pos:] -	} - -	l = d.l -	if d.h>>61&3 == 3 { -		// Bits: 1*sign 2*ignored 14*exponent 111*significand. -		// Implicit 0b100 prefix in significand. -		e = int(d.h>>47&(1<<14-1)) - 6176 -		//h = 4<<47 | d.h&(1<<47-1) -		// Spec says all of these values are out of range. -		h, l = 0, 0 -	} else { -		// Bits: 1*sign 14*exponent 113*significand -		e = int(d.h>>49&(1<<14-1)) - 6176 -		h = d.h & (1<<49 - 1) -	} - -	// Would be handled by the logic below, but that's trivial and common. -	if h == 0 && l == 0 && e == 0 { -		return "-0"[pos:] -	} - -	var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero. -	var last = len(repr) -	var i = len(repr) -	var dot = len(repr) + e -	var rem uint32 -Loop: -	for d9 := 0; d9 < 5; d9++ { -		h, l, rem = divmod(h, l, 1e9) -		for d1 := 0; d1 < 9; d1++ { -			// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc. -			if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) { -				e += len(repr) - i -				i-- -				repr[i] = '.' -				last = i - 1 -				dot = len(repr) // Unmark. -			} -			c := '0' + byte(rem%10) -			rem /= 10 -			i-- -			repr[i] = c -			// Handle "0E+3", "1E+3", etc. -			if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) { -				last = i -				break Loop -			} -			if c != '0' { -				last = i -			} -			// Break early. Works without it, but why. -			if dot > i && l == 0 && h == 0 && rem == 0 { -				break Loop -			} -		} -	} -	repr[last-1] = '-' -	last-- - -	if e > 0 { -		return string(repr[last+pos:]) + "E+" + strconv.Itoa(e) -	} -	if e < 0 { -		return string(repr[last+pos:]) + "E" + strconv.Itoa(e) -	} -	return string(repr[last+pos:]) -} - -func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) { -	div64 := uint64(div) -	a := h >> 32 -	aq := a / div64 -	ar := a % div64 -	b := ar<<32 + h&(1<<32-1) -	bq := b / div64 -	br := b % div64 -	c := br<<32 + l>>32 -	cq := c / div64 -	cr := c % div64 -	d := cr<<32 + l&(1<<32-1) -	dq := d / div64 -	dr := d % div64 -	return (aq<<32 | bq), (cq<<32 | dq), uint32(dr) -} - -var dNaN = Decimal128{0x1F << 58, 0} -var dPosInf = Decimal128{0x1E << 58, 0} -var dNegInf = Decimal128{0x3E << 58, 0} - -func dErr(s string) (Decimal128, error) { -	return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s) -} - -func ParseDecimal128(s string) (Decimal128, error) { -	orig := s -	if s == "" { -		return dErr(orig) -	} -	neg := s[0] == '-' -	if neg || s[0] == '+' { -		s = s[1:] -	} - -	if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') { -		if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") { -			return dNaN, nil -		} -		if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") { -			if neg { -				return dNegInf, nil -			} -			return dPosInf, nil -		} -		return dErr(orig) -	} - -	var h, l uint64 -	var e int - -	var add, ovr uint32 -	var mul uint32 = 1 -	var dot = -1 -	var digits = 0 -	var i = 0 -	for i < len(s) { -		c := s[i] -		if mul == 1e9 { -			h, l, ovr = muladd(h, l, mul, add) -			mul, add = 1, 0 -			if ovr > 0 || h&((1<<15-1)<<49) > 0 { -				return dErr(orig) -			} -		} -		if c >= '0' && c <= '9' { -			i++ -			if c > '0' || digits > 0 { -				digits++ -			} -			if digits > 34 { -				if c == '0' { -					// Exact rounding. -					e++ -					continue -				} -				return dErr(orig) -			} -			mul *= 10 -			add *= 10 -			add += uint32(c - '0') -			continue -		} -		if c == '.' { -			i++ -			if dot >= 0 || i == 1 && len(s) == 1 { -				return dErr(orig) -			} -			if i == len(s) { -				break -			} -			if s[i] < '0' || s[i] > '9' || e > 0 { -				return dErr(orig) -			} -			dot = i -			continue -		} -		break -	} -	if i == 0 { -		return dErr(orig) -	} -	if mul > 1 { -		h, l, ovr = muladd(h, l, mul, add) -		if ovr > 0 || h&((1<<15-1)<<49) > 0 { -			return dErr(orig) -		} -	} -	if dot >= 0 { -		e += dot - i -	} -	if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') { -		i++ -		eneg := s[i] == '-' -		if eneg || s[i] == '+' { -			i++ -			if i == len(s) { -				return dErr(orig) -			} -		} -		n := 0 -		for i < len(s) && n < 1e4 { -			c := s[i] -			i++ -			if c < '0' || c > '9' { -				return dErr(orig) -			} -			n *= 10 -			n += int(c - '0') -		} -		if eneg { -			n = -n -		} -		e += n -		for e < -6176 { -			// Subnormal. -			var div uint32 = 1 -			for div < 1e9 && e < -6176 { -				div *= 10 -				e++ -			} -			var rem uint32 -			h, l, rem = divmod(h, l, div) -			if rem > 0 { -				return dErr(orig) -			} -		} -		for e > 6111 { -			// Clamped. -			var mul uint32 = 1 -			for mul < 1e9 && e > 6111 { -				mul *= 10 -				e-- -			} -			h, l, ovr = muladd(h, l, mul, 0) -			if ovr > 0 || h&((1<<15-1)<<49) > 0 { -				return dErr(orig) -			} -		} -		if e < -6176 || e > 6111 { -			return dErr(orig) -		} -	} - -	if i < len(s) { -		return dErr(orig) -	} - -	h |= uint64(e+6176) & uint64(1<<14-1) << 49 -	if neg { -		h |= 1 << 63 -	} -	return Decimal128{h, l}, nil -} - -func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) { -	mul64 := uint64(mul) -	a := mul64 * (l & (1<<32 - 1)) -	b := a>>32 + mul64*(l>>32) -	c := b>>32 + mul64*(h&(1<<32-1)) -	d := c>>32 + mul64*(h>>32) - -	a = a&(1<<32-1) + uint64(add) -	b = b&(1<<32-1) + a>>32 -	c = c&(1<<32-1) + b>>32 -	d = d&(1<<32-1) + c>>32 - -	return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32) -} diff --git a/vendor/gopkg.in/mgo.v2/bson/decode.go b/vendor/gopkg.in/mgo.v2/bson/decode.go deleted file mode 100644 index 7c2d841..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/decode.go +++ /dev/null @@ -1,849 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// gobson - BSON library for Go. - -package bson - -import ( -	"fmt" -	"math" -	"net/url" -	"reflect" -	"strconv" -	"sync" -	"time" -) - -type decoder struct { -	in      []byte -	i       int -	docType reflect.Type -} - -var typeM = reflect.TypeOf(M{}) - -func newDecoder(in []byte) *decoder { -	return &decoder{in, 0, typeM} -} - -// -------------------------------------------------------------------------- -// Some helper functions. - -func corrupted() { -	panic("Document is corrupted") -} - -func settableValueOf(i interface{}) reflect.Value { -	v := reflect.ValueOf(i) -	sv := reflect.New(v.Type()).Elem() -	sv.Set(v) -	return sv -} - -// -------------------------------------------------------------------------- -// Unmarshaling of documents. - -const ( -	setterUnknown = iota -	setterNone -	setterType -	setterAddr -) - -var setterStyles map[reflect.Type]int -var setterIface reflect.Type -var setterMutex sync.RWMutex - -func init() { -	var iface Setter -	setterIface = reflect.TypeOf(&iface).Elem() -	setterStyles = make(map[reflect.Type]int) -} - -func setterStyle(outt reflect.Type) int { -	setterMutex.RLock() -	style := setterStyles[outt] -	setterMutex.RUnlock() -	if style == setterUnknown { -		setterMutex.Lock() -		defer setterMutex.Unlock() -		if outt.Implements(setterIface) { -			setterStyles[outt] = setterType -		} else if reflect.PtrTo(outt).Implements(setterIface) { -			setterStyles[outt] = setterAddr -		} else { -			setterStyles[outt] = setterNone -		} -		style = setterStyles[outt] -	} -	return style -} - -func getSetter(outt reflect.Type, out reflect.Value) Setter { -	style := setterStyle(outt) -	if style == setterNone { -		return nil -	} -	if style == setterAddr { -		if !out.CanAddr() { -			return nil -		} -		out = out.Addr() -	} else if outt.Kind() == reflect.Ptr && out.IsNil() { -		out.Set(reflect.New(outt.Elem())) -	} -	return out.Interface().(Setter) -} - -func clearMap(m reflect.Value) { -	var none reflect.Value -	for _, k := range m.MapKeys() { -		m.SetMapIndex(k, none) -	} -} - -func (d *decoder) readDocTo(out reflect.Value) { -	var elemType reflect.Type -	outt := out.Type() -	outk := outt.Kind() - -	for { -		if outk == reflect.Ptr && out.IsNil() { -			out.Set(reflect.New(outt.Elem())) -		} -		if setter := getSetter(outt, out); setter != nil { -			var raw Raw -			d.readDocTo(reflect.ValueOf(&raw)) -			err := setter.SetBSON(raw) -			if _, ok := err.(*TypeError); err != nil && !ok { -				panic(err) -			} -			return -		} -		if outk == reflect.Ptr { -			out = out.Elem() -			outt = out.Type() -			outk = out.Kind() -			continue -		} -		break -	} - -	var fieldsMap map[string]fieldInfo -	var inlineMap reflect.Value -	start := d.i - -	origout := out -	if outk == reflect.Interface { -		if d.docType.Kind() == reflect.Map { -			mv := reflect.MakeMap(d.docType) -			out.Set(mv) -			out = mv -		} else { -			dv := reflect.New(d.docType).Elem() -			out.Set(dv) -			out = dv -		} -		outt = out.Type() -		outk = outt.Kind() -	} - -	docType := d.docType -	keyType := typeString -	convertKey := false -	switch outk { -	case reflect.Map: -		keyType = outt.Key() -		if keyType.Kind() != reflect.String { -			panic("BSON map must have string keys. Got: " + outt.String()) -		} -		if keyType != typeString { -			convertKey = true -		} -		elemType = outt.Elem() -		if elemType == typeIface { -			d.docType = outt -		} -		if out.IsNil() { -			out.Set(reflect.MakeMap(out.Type())) -		} else if out.Len() > 0 { -			clearMap(out) -		} -	case reflect.Struct: -		if outt != typeRaw { -			sinfo, err := getStructInfo(out.Type()) -			if err != nil { -				panic(err) -			} -			fieldsMap = sinfo.FieldsMap -			out.Set(sinfo.Zero) -			if sinfo.InlineMap != -1 { -				inlineMap = out.Field(sinfo.InlineMap) -				if !inlineMap.IsNil() && inlineMap.Len() > 0 { -					clearMap(inlineMap) -				} -				elemType = inlineMap.Type().Elem() -				if elemType == typeIface { -					d.docType = inlineMap.Type() -				} -			} -		} -	case reflect.Slice: -		switch outt.Elem() { -		case typeDocElem: -			origout.Set(d.readDocElems(outt)) -			return -		case typeRawDocElem: -			origout.Set(d.readRawDocElems(outt)) -			return -		} -		fallthrough -	default: -		panic("Unsupported document type for unmarshalling: " + out.Type().String()) -	} - -	end := int(d.readInt32()) -	end += d.i - 4 -	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { -		corrupted() -	} -	for d.in[d.i] != '\x00' { -		kind := d.readByte() -		name := d.readCStr() -		if d.i >= end { -			corrupted() -		} - -		switch outk { -		case reflect.Map: -			e := reflect.New(elemType).Elem() -			if d.readElemTo(e, kind) { -				k := reflect.ValueOf(name) -				if convertKey { -					k = k.Convert(keyType) -				} -				out.SetMapIndex(k, e) -			} -		case reflect.Struct: -			if outt == typeRaw { -				d.dropElem(kind) -			} else { -				if info, ok := fieldsMap[name]; ok { -					if info.Inline == nil { -						d.readElemTo(out.Field(info.Num), kind) -					} else { -						d.readElemTo(out.FieldByIndex(info.Inline), kind) -					} -				} else if inlineMap.IsValid() { -					if inlineMap.IsNil() { -						inlineMap.Set(reflect.MakeMap(inlineMap.Type())) -					} -					e := reflect.New(elemType).Elem() -					if d.readElemTo(e, kind) { -						inlineMap.SetMapIndex(reflect.ValueOf(name), e) -					} -				} else { -					d.dropElem(kind) -				} -			} -		case reflect.Slice: -		} - -		if d.i >= end { -			corrupted() -		} -	} -	d.i++ // '\x00' -	if d.i != end { -		corrupted() -	} -	d.docType = docType - -	if outt == typeRaw { -		out.Set(reflect.ValueOf(Raw{0x03, d.in[start:d.i]})) -	} -} - -func (d *decoder) readArrayDocTo(out reflect.Value) { -	end := int(d.readInt32()) -	end += d.i - 4 -	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { -		corrupted() -	} -	i := 0 -	l := out.Len() -	for d.in[d.i] != '\x00' { -		if i >= l { -			panic("Length mismatch on array field") -		} -		kind := d.readByte() -		for d.i < end && d.in[d.i] != '\x00' { -			d.i++ -		} -		if d.i >= end { -			corrupted() -		} -		d.i++ -		d.readElemTo(out.Index(i), kind) -		if d.i >= end { -			corrupted() -		} -		i++ -	} -	if i != l { -		panic("Length mismatch on array field") -	} -	d.i++ // '\x00' -	if d.i != end { -		corrupted() -	} -} - -func (d *decoder) readSliceDoc(t reflect.Type) interface{} { -	tmp := make([]reflect.Value, 0, 8) -	elemType := t.Elem() -	if elemType == typeRawDocElem { -		d.dropElem(0x04) -		return reflect.Zero(t).Interface() -	} - -	end := int(d.readInt32()) -	end += d.i - 4 -	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { -		corrupted() -	} -	for d.in[d.i] != '\x00' { -		kind := d.readByte() -		for d.i < end && d.in[d.i] != '\x00' { -			d.i++ -		} -		if d.i >= end { -			corrupted() -		} -		d.i++ -		e := reflect.New(elemType).Elem() -		if d.readElemTo(e, kind) { -			tmp = append(tmp, e) -		} -		if d.i >= end { -			corrupted() -		} -	} -	d.i++ // '\x00' -	if d.i != end { -		corrupted() -	} - -	n := len(tmp) -	slice := reflect.MakeSlice(t, n, n) -	for i := 0; i != n; i++ { -		slice.Index(i).Set(tmp[i]) -	} -	return slice.Interface() -} - -var typeSlice = reflect.TypeOf([]interface{}{}) -var typeIface = typeSlice.Elem() - -func (d *decoder) readDocElems(typ reflect.Type) reflect.Value { -	docType := d.docType -	d.docType = typ -	slice := make([]DocElem, 0, 8) -	d.readDocWith(func(kind byte, name string) { -		e := DocElem{Name: name} -		v := reflect.ValueOf(&e.Value) -		if d.readElemTo(v.Elem(), kind) { -			slice = append(slice, e) -		} -	}) -	slicev := reflect.New(typ).Elem() -	slicev.Set(reflect.ValueOf(slice)) -	d.docType = docType -	return slicev -} - -func (d *decoder) readRawDocElems(typ reflect.Type) reflect.Value { -	docType := d.docType -	d.docType = typ -	slice := make([]RawDocElem, 0, 8) -	d.readDocWith(func(kind byte, name string) { -		e := RawDocElem{Name: name} -		v := reflect.ValueOf(&e.Value) -		if d.readElemTo(v.Elem(), kind) { -			slice = append(slice, e) -		} -	}) -	slicev := reflect.New(typ).Elem() -	slicev.Set(reflect.ValueOf(slice)) -	d.docType = docType -	return slicev -} - -func (d *decoder) readDocWith(f func(kind byte, name string)) { -	end := int(d.readInt32()) -	end += d.i - 4 -	if end <= d.i || end > len(d.in) || d.in[end-1] != '\x00' { -		corrupted() -	} -	for d.in[d.i] != '\x00' { -		kind := d.readByte() -		name := d.readCStr() -		if d.i >= end { -			corrupted() -		} -		f(kind, name) -		if d.i >= end { -			corrupted() -		} -	} -	d.i++ // '\x00' -	if d.i != end { -		corrupted() -	} -} - -// -------------------------------------------------------------------------- -// Unmarshaling of individual elements within a document. - -var blackHole = settableValueOf(struct{}{}) - -func (d *decoder) dropElem(kind byte) { -	d.readElemTo(blackHole, kind) -} - -// Attempt to decode an element from the document and put it into out. -// If the types are not compatible, the returned ok value will be -// false and out will be unchanged. -func (d *decoder) readElemTo(out reflect.Value, kind byte) (good bool) { - -	start := d.i - -	if kind == 0x03 { -		// Delegate unmarshaling of documents. -		outt := out.Type() -		outk := out.Kind() -		switch outk { -		case reflect.Interface, reflect.Ptr, reflect.Struct, reflect.Map: -			d.readDocTo(out) -			return true -		} -		if setterStyle(outt) != setterNone { -			d.readDocTo(out) -			return true -		} -		if outk == reflect.Slice { -			switch outt.Elem() { -			case typeDocElem: -				out.Set(d.readDocElems(outt)) -			case typeRawDocElem: -				out.Set(d.readRawDocElems(outt)) -			default: -				d.readDocTo(blackHole) -			} -			return true -		} -		d.readDocTo(blackHole) -		return true -	} - -	var in interface{} - -	switch kind { -	case 0x01: // Float64 -		in = d.readFloat64() -	case 0x02: // UTF-8 string -		in = d.readStr() -	case 0x03: // Document -		panic("Can't happen. Handled above.") -	case 0x04: // Array -		outt := out.Type() -		if setterStyle(outt) != setterNone { -			// Skip the value so its data is handed to the setter below. -			d.dropElem(kind) -			break -		} -		for outt.Kind() == reflect.Ptr { -			outt = outt.Elem() -		} -		switch outt.Kind() { -		case reflect.Array: -			d.readArrayDocTo(out) -			return true -		case reflect.Slice: -			in = d.readSliceDoc(outt) -		default: -			in = d.readSliceDoc(typeSlice) -		} -	case 0x05: // Binary -		b := d.readBinary() -		if b.Kind == 0x00 || b.Kind == 0x02 { -			in = b.Data -		} else { -			in = b -		} -	case 0x06: // Undefined (obsolete, but still seen in the wild) -		in = Undefined -	case 0x07: // ObjectId -		in = ObjectId(d.readBytes(12)) -	case 0x08: // Bool -		in = d.readBool() -	case 0x09: // Timestamp -		// MongoDB handles timestamps as milliseconds. -		i := d.readInt64() -		if i == -62135596800000 { -			in = time.Time{} // In UTC for convenience. -		} else { -			in = time.Unix(i/1e3, i%1e3*1e6) -		} -	case 0x0A: // Nil -		in = nil -	case 0x0B: // RegEx -		in = d.readRegEx() -	case 0x0C: -		in = DBPointer{Namespace: d.readStr(), Id: ObjectId(d.readBytes(12))} -	case 0x0D: // JavaScript without scope -		in = JavaScript{Code: d.readStr()} -	case 0x0E: // Symbol -		in = Symbol(d.readStr()) -	case 0x0F: // JavaScript with scope -		d.i += 4 // Skip length -		js := JavaScript{d.readStr(), make(M)} -		d.readDocTo(reflect.ValueOf(js.Scope)) -		in = js -	case 0x10: // Int32 -		in = int(d.readInt32()) -	case 0x11: // Mongo-specific timestamp -		in = MongoTimestamp(d.readInt64()) -	case 0x12: // Int64 -		in = d.readInt64() -	case 0x13: // Decimal128 -		in = Decimal128{ -			l: uint64(d.readInt64()), -			h: uint64(d.readInt64()), -		} -	case 0x7F: // Max key -		in = MaxKey -	case 0xFF: // Min key -		in = MinKey -	default: -		panic(fmt.Sprintf("Unknown element kind (0x%02X)", kind)) -	} - -	outt := out.Type() - -	if outt == typeRaw { -		out.Set(reflect.ValueOf(Raw{kind, d.in[start:d.i]})) -		return true -	} - -	if setter := getSetter(outt, out); setter != nil { -		err := setter.SetBSON(Raw{kind, d.in[start:d.i]}) -		if err == SetZero { -			out.Set(reflect.Zero(outt)) -			return true -		} -		if err == nil { -			return true -		} -		if _, ok := err.(*TypeError); !ok { -			panic(err) -		} -		return false -	} - -	if in == nil { -		out.Set(reflect.Zero(outt)) -		return true -	} - -	outk := outt.Kind() - -	// Dereference and initialize pointer if necessary. -	first := true -	for outk == reflect.Ptr { -		if !out.IsNil() { -			out = out.Elem() -		} else { -			elem := reflect.New(outt.Elem()) -			if first { -				// Only set if value is compatible. -				first = false -				defer func(out, elem reflect.Value) { -					if good { -						out.Set(elem) -					} -				}(out, elem) -			} else { -				out.Set(elem) -			} -			out = elem -		} -		outt = out.Type() -		outk = outt.Kind() -	} - -	inv := reflect.ValueOf(in) -	if outt == inv.Type() { -		out.Set(inv) -		return true -	} - -	switch outk { -	case reflect.Interface: -		out.Set(inv) -		return true -	case reflect.String: -		switch inv.Kind() { -		case reflect.String: -			out.SetString(inv.String()) -			return true -		case reflect.Slice: -			if b, ok := in.([]byte); ok { -				out.SetString(string(b)) -				return true -			} -		case reflect.Int, reflect.Int64: -			if outt == typeJSONNumber { -				out.SetString(strconv.FormatInt(inv.Int(), 10)) -				return true -			} -		case reflect.Float64: -			if outt == typeJSONNumber { -				out.SetString(strconv.FormatFloat(inv.Float(), 'f', -1, 64)) -				return true -			} -		} -	case reflect.Slice, reflect.Array: -		// Remember, array (0x04) slices are built with the correct -		// element type.  If we are here, must be a cross BSON kind -		// conversion (e.g. 0x05 unmarshalling on string). -		if outt.Elem().Kind() != reflect.Uint8 { -			break -		} -		switch inv.Kind() { -		case reflect.String: -			slice := []byte(inv.String()) -			out.Set(reflect.ValueOf(slice)) -			return true -		case reflect.Slice: -			switch outt.Kind() { -			case reflect.Array: -				reflect.Copy(out, inv) -			case reflect.Slice: -				out.SetBytes(inv.Bytes()) -			} -			return true -		} -	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -		switch inv.Kind() { -		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -			out.SetInt(inv.Int()) -			return true -		case reflect.Float32, reflect.Float64: -			out.SetInt(int64(inv.Float())) -			return true -		case reflect.Bool: -			if inv.Bool() { -				out.SetInt(1) -			} else { -				out.SetInt(0) -			} -			return true -		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -			panic("can't happen: no uint types in BSON (!?)") -		} -	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -		switch inv.Kind() { -		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -			out.SetUint(uint64(inv.Int())) -			return true -		case reflect.Float32, reflect.Float64: -			out.SetUint(uint64(inv.Float())) -			return true -		case reflect.Bool: -			if inv.Bool() { -				out.SetUint(1) -			} else { -				out.SetUint(0) -			} -			return true -		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -			panic("Can't happen. No uint types in BSON.") -		} -	case reflect.Float32, reflect.Float64: -		switch inv.Kind() { -		case reflect.Float32, reflect.Float64: -			out.SetFloat(inv.Float()) -			return true -		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -			out.SetFloat(float64(inv.Int())) -			return true -		case reflect.Bool: -			if inv.Bool() { -				out.SetFloat(1) -			} else { -				out.SetFloat(0) -			} -			return true -		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -			panic("Can't happen. No uint types in BSON?") -		} -	case reflect.Bool: -		switch inv.Kind() { -		case reflect.Bool: -			out.SetBool(inv.Bool()) -			return true -		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -			out.SetBool(inv.Int() != 0) -			return true -		case reflect.Float32, reflect.Float64: -			out.SetBool(inv.Float() != 0) -			return true -		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -			panic("Can't happen. No uint types in BSON?") -		} -	case reflect.Struct: -		if outt == typeURL && inv.Kind() == reflect.String { -			u, err := url.Parse(inv.String()) -			if err != nil { -				panic(err) -			} -			out.Set(reflect.ValueOf(u).Elem()) -			return true -		} -		if outt == typeBinary { -			if b, ok := in.([]byte); ok { -				out.Set(reflect.ValueOf(Binary{Data: b})) -				return true -			} -		} -	} - -	return false -} - -// -------------------------------------------------------------------------- -// Parsers of basic types. - -func (d *decoder) readRegEx() RegEx { -	re := RegEx{} -	re.Pattern = d.readCStr() -	re.Options = d.readCStr() -	return re -} - -func (d *decoder) readBinary() Binary { -	l := d.readInt32() -	b := Binary{} -	b.Kind = d.readByte() -	b.Data = d.readBytes(l) -	if b.Kind == 0x02 && len(b.Data) >= 4 { -		// Weird obsolete format with redundant length. -		b.Data = b.Data[4:] -	} -	return b -} - -func (d *decoder) readStr() string { -	l := d.readInt32() -	b := d.readBytes(l - 1) -	if d.readByte() != '\x00' { -		corrupted() -	} -	return string(b) -} - -func (d *decoder) readCStr() string { -	start := d.i -	end := start -	l := len(d.in) -	for ; end != l; end++ { -		if d.in[end] == '\x00' { -			break -		} -	} -	d.i = end + 1 -	if d.i > l { -		corrupted() -	} -	return string(d.in[start:end]) -} - -func (d *decoder) readBool() bool { -	b := d.readByte() -	if b == 0 { -		return false -	} -	if b == 1 { -		return true -	} -	panic(fmt.Sprintf("encoded boolean must be 1 or 0, found %d", b)) -} - -func (d *decoder) readFloat64() float64 { -	return math.Float64frombits(uint64(d.readInt64())) -} - -func (d *decoder) readInt32() int32 { -	b := d.readBytes(4) -	return int32((uint32(b[0]) << 0) | -		(uint32(b[1]) << 8) | -		(uint32(b[2]) << 16) | -		(uint32(b[3]) << 24)) -} - -func (d *decoder) readInt64() int64 { -	b := d.readBytes(8) -	return int64((uint64(b[0]) << 0) | -		(uint64(b[1]) << 8) | -		(uint64(b[2]) << 16) | -		(uint64(b[3]) << 24) | -		(uint64(b[4]) << 32) | -		(uint64(b[5]) << 40) | -		(uint64(b[6]) << 48) | -		(uint64(b[7]) << 56)) -} - -func (d *decoder) readByte() byte { -	i := d.i -	d.i++ -	if d.i > len(d.in) { -		corrupted() -	} -	return d.in[i] -} - -func (d *decoder) readBytes(length int32) []byte { -	if length < 0 { -		corrupted() -	} -	start := d.i -	d.i += int(length) -	if d.i < start || d.i > len(d.in) { -		corrupted() -	} -	return d.in[start : start+int(length)] -} diff --git a/vendor/gopkg.in/mgo.v2/bson/encode.go b/vendor/gopkg.in/mgo.v2/bson/encode.go deleted file mode 100644 index add39e8..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/encode.go +++ /dev/null @@ -1,514 +0,0 @@ -// BSON library for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// gobson - BSON library for Go. - -package bson - -import ( -	"encoding/json" -	"fmt" -	"math" -	"net/url" -	"reflect" -	"strconv" -	"time" -) - -// -------------------------------------------------------------------------- -// Some internal infrastructure. - -var ( -	typeBinary         = reflect.TypeOf(Binary{}) -	typeObjectId       = reflect.TypeOf(ObjectId("")) -	typeDBPointer      = reflect.TypeOf(DBPointer{"", ObjectId("")}) -	typeSymbol         = reflect.TypeOf(Symbol("")) -	typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0)) -	typeOrderKey       = reflect.TypeOf(MinKey) -	typeDocElem        = reflect.TypeOf(DocElem{}) -	typeRawDocElem     = reflect.TypeOf(RawDocElem{}) -	typeRaw            = reflect.TypeOf(Raw{}) -	typeURL            = reflect.TypeOf(url.URL{}) -	typeTime           = reflect.TypeOf(time.Time{}) -	typeString         = reflect.TypeOf("") -	typeJSONNumber     = reflect.TypeOf(json.Number("")) -) - -const itoaCacheSize = 32 - -var itoaCache []string - -func init() { -	itoaCache = make([]string, itoaCacheSize) -	for i := 0; i != itoaCacheSize; i++ { -		itoaCache[i] = strconv.Itoa(i) -	} -} - -func itoa(i int) string { -	if i < itoaCacheSize { -		return itoaCache[i] -	} -	return strconv.Itoa(i) -} - -// -------------------------------------------------------------------------- -// Marshaling of the document value itself. - -type encoder struct { -	out []byte -} - -func (e *encoder) addDoc(v reflect.Value) { -	for { -		if vi, ok := v.Interface().(Getter); ok { -			getv, err := vi.GetBSON() -			if err != nil { -				panic(err) -			} -			v = reflect.ValueOf(getv) -			continue -		} -		if v.Kind() == reflect.Ptr { -			v = v.Elem() -			continue -		} -		break -	} - -	if v.Type() == typeRaw { -		raw := v.Interface().(Raw) -		if raw.Kind != 0x03 && raw.Kind != 0x00 { -			panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document") -		} -		if len(raw.Data) == 0 { -			panic("Attempted to marshal empty Raw document") -		} -		e.addBytes(raw.Data...) -		return -	} - -	start := e.reserveInt32() - -	switch v.Kind() { -	case reflect.Map: -		e.addMap(v) -	case reflect.Struct: -		e.addStruct(v) -	case reflect.Array, reflect.Slice: -		e.addSlice(v) -	default: -		panic("Can't marshal " + v.Type().String() + " as a BSON document") -	} - -	e.addBytes(0) -	e.setInt32(start, int32(len(e.out)-start)) -} - -func (e *encoder) addMap(v reflect.Value) { -	for _, k := range v.MapKeys() { -		e.addElem(k.String(), v.MapIndex(k), false) -	} -} - -func (e *encoder) addStruct(v reflect.Value) { -	sinfo, err := getStructInfo(v.Type()) -	if err != nil { -		panic(err) -	} -	var value reflect.Value -	if sinfo.InlineMap >= 0 { -		m := v.Field(sinfo.InlineMap) -		if m.Len() > 0 { -			for _, k := range m.MapKeys() { -				ks := k.String() -				if _, found := sinfo.FieldsMap[ks]; found { -					panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks)) -				} -				e.addElem(ks, m.MapIndex(k), false) -			} -		} -	} -	for _, info := range sinfo.FieldsList { -		if info.Inline == nil { -			value = v.Field(info.Num) -		} else { -			value = v.FieldByIndex(info.Inline) -		} -		if info.OmitEmpty && isZero(value) { -			continue -		} -		e.addElem(info.Key, value, info.MinSize) -	} -} - -func isZero(v reflect.Value) bool { -	switch v.Kind() { -	case reflect.String: -		return len(v.String()) == 0 -	case reflect.Ptr, reflect.Interface: -		return v.IsNil() -	case reflect.Slice: -		return v.Len() == 0 -	case reflect.Map: -		return v.Len() == 0 -	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -		return v.Int() == 0 -	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -		return v.Uint() == 0 -	case reflect.Float32, reflect.Float64: -		return v.Float() == 0 -	case reflect.Bool: -		return !v.Bool() -	case reflect.Struct: -		vt := v.Type() -		if vt == typeTime { -			return v.Interface().(time.Time).IsZero() -		} -		for i := 0; i < v.NumField(); i++ { -			if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous { -				continue // Private field -			} -			if !isZero(v.Field(i)) { -				return false -			} -		} -		return true -	} -	return false -} - -func (e *encoder) addSlice(v reflect.Value) { -	vi := v.Interface() -	if d, ok := vi.(D); ok { -		for _, elem := range d { -			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) -		} -		return -	} -	if d, ok := vi.(RawD); ok { -		for _, elem := range d { -			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) -		} -		return -	} -	l := v.Len() -	et := v.Type().Elem() -	if et == typeDocElem { -		for i := 0; i < l; i++ { -			elem := v.Index(i).Interface().(DocElem) -			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) -		} -		return -	} -	if et == typeRawDocElem { -		for i := 0; i < l; i++ { -			elem := v.Index(i).Interface().(RawDocElem) -			e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) -		} -		return -	} -	for i := 0; i < l; i++ { -		e.addElem(itoa(i), v.Index(i), false) -	} -} - -// -------------------------------------------------------------------------- -// Marshaling of elements in a document. - -func (e *encoder) addElemName(kind byte, name string) { -	e.addBytes(kind) -	e.addBytes([]byte(name)...) -	e.addBytes(0) -} - -func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { - -	if !v.IsValid() { -		e.addElemName(0x0A, name) -		return -	} - -	if getter, ok := v.Interface().(Getter); ok { -		getv, err := getter.GetBSON() -		if err != nil { -			panic(err) -		} -		e.addElem(name, reflect.ValueOf(getv), minSize) -		return -	} - -	switch v.Kind() { - -	case reflect.Interface: -		e.addElem(name, v.Elem(), minSize) - -	case reflect.Ptr: -		e.addElem(name, v.Elem(), minSize) - -	case reflect.String: -		s := v.String() -		switch v.Type() { -		case typeObjectId: -			if len(s) != 12 { -				panic("ObjectIDs must be exactly 12 bytes long (got " + -					strconv.Itoa(len(s)) + ")") -			} -			e.addElemName(0x07, name) -			e.addBytes([]byte(s)...) -		case typeSymbol: -			e.addElemName(0x0E, name) -			e.addStr(s) -		case typeJSONNumber: -			n := v.Interface().(json.Number) -			if i, err := n.Int64(); err == nil { -				e.addElemName(0x12, name) -				e.addInt64(i) -			} else if f, err := n.Float64(); err == nil { -				e.addElemName(0x01, name) -				e.addFloat64(f) -			} else { -				panic("failed to convert json.Number to a number: " + s) -			} -		default: -			e.addElemName(0x02, name) -			e.addStr(s) -		} - -	case reflect.Float32, reflect.Float64: -		e.addElemName(0x01, name) -		e.addFloat64(v.Float()) - -	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -		u := v.Uint() -		if int64(u) < 0 { -			panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") -		} else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { -			e.addElemName(0x10, name) -			e.addInt32(int32(u)) -		} else { -			e.addElemName(0x12, name) -			e.addInt64(int64(u)) -		} - -	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -		switch v.Type() { -		case typeMongoTimestamp: -			e.addElemName(0x11, name) -			e.addInt64(v.Int()) - -		case typeOrderKey: -			if v.Int() == int64(MaxKey) { -				e.addElemName(0x7F, name) -			} else { -				e.addElemName(0xFF, name) -			} - -		default: -			i := v.Int() -			if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { -				// It fits into an int32, encode as such. -				e.addElemName(0x10, name) -				e.addInt32(int32(i)) -			} else { -				e.addElemName(0x12, name) -				e.addInt64(i) -			} -		} - -	case reflect.Bool: -		e.addElemName(0x08, name) -		if v.Bool() { -			e.addBytes(1) -		} else { -			e.addBytes(0) -		} - -	case reflect.Map: -		e.addElemName(0x03, name) -		e.addDoc(v) - -	case reflect.Slice: -		vt := v.Type() -		et := vt.Elem() -		if et.Kind() == reflect.Uint8 { -			e.addElemName(0x05, name) -			e.addBinary(0x00, v.Bytes()) -		} else if et == typeDocElem || et == typeRawDocElem { -			e.addElemName(0x03, name) -			e.addDoc(v) -		} else { -			e.addElemName(0x04, name) -			e.addDoc(v) -		} - -	case reflect.Array: -		et := v.Type().Elem() -		if et.Kind() == reflect.Uint8 { -			e.addElemName(0x05, name) -			if v.CanAddr() { -				e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte)) -			} else { -				n := v.Len() -				e.addInt32(int32(n)) -				e.addBytes(0x00) -				for i := 0; i < n; i++ { -					el := v.Index(i) -					e.addBytes(byte(el.Uint())) -				} -			} -		} else { -			e.addElemName(0x04, name) -			e.addDoc(v) -		} - -	case reflect.Struct: -		switch s := v.Interface().(type) { - -		case Raw: -			kind := s.Kind -			if kind == 0x00 { -				kind = 0x03 -			} -			if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F { -				panic("Attempted to marshal empty Raw document") -			} -			e.addElemName(kind, name) -			e.addBytes(s.Data...) - -		case Binary: -			e.addElemName(0x05, name) -			e.addBinary(s.Kind, s.Data) - -		case Decimal128: -			e.addElemName(0x13, name) -			e.addInt64(int64(s.l)) -			e.addInt64(int64(s.h)) - -		case DBPointer: -			e.addElemName(0x0C, name) -			e.addStr(s.Namespace) -			if len(s.Id) != 12 { -				panic("ObjectIDs must be exactly 12 bytes long (got " + -					strconv.Itoa(len(s.Id)) + ")") -			} -			e.addBytes([]byte(s.Id)...) - -		case RegEx: -			e.addElemName(0x0B, name) -			e.addCStr(s.Pattern) -			e.addCStr(s.Options) - -		case JavaScript: -			if s.Scope == nil { -				e.addElemName(0x0D, name) -				e.addStr(s.Code) -			} else { -				e.addElemName(0x0F, name) -				start := e.reserveInt32() -				e.addStr(s.Code) -				e.addDoc(reflect.ValueOf(s.Scope)) -				e.setInt32(start, int32(len(e.out)-start)) -			} - -		case time.Time: -			// MongoDB handles timestamps as milliseconds. -			e.addElemName(0x09, name) -			e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) - -		case url.URL: -			e.addElemName(0x02, name) -			e.addStr(s.String()) - -		case undefined: -			e.addElemName(0x06, name) - -		default: -			e.addElemName(0x03, name) -			e.addDoc(v) -		} - -	default: -		panic("Can't marshal " + v.Type().String() + " in a BSON document") -	} -} - -// -------------------------------------------------------------------------- -// Marshaling of base types. - -func (e *encoder) addBinary(subtype byte, v []byte) { -	if subtype == 0x02 { -		// Wonder how that brilliant idea came to life. Obsolete, luckily. -		e.addInt32(int32(len(v) + 4)) -		e.addBytes(subtype) -		e.addInt32(int32(len(v))) -	} else { -		e.addInt32(int32(len(v))) -		e.addBytes(subtype) -	} -	e.addBytes(v...) -} - -func (e *encoder) addStr(v string) { -	e.addInt32(int32(len(v) + 1)) -	e.addCStr(v) -} - -func (e *encoder) addCStr(v string) { -	e.addBytes([]byte(v)...) -	e.addBytes(0) -} - -func (e *encoder) reserveInt32() (pos int) { -	pos = len(e.out) -	e.addBytes(0, 0, 0, 0) -	return pos -} - -func (e *encoder) setInt32(pos int, v int32) { -	e.out[pos+0] = byte(v) -	e.out[pos+1] = byte(v >> 8) -	e.out[pos+2] = byte(v >> 16) -	e.out[pos+3] = byte(v >> 24) -} - -func (e *encoder) addInt32(v int32) { -	u := uint32(v) -	e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24)) -} - -func (e *encoder) addInt64(v int64) { -	u := uint64(v) -	e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24), -		byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56)) -} - -func (e *encoder) addFloat64(v float64) { -	e.addInt64(int64(math.Float64bits(v))) -} - -func (e *encoder) addBytes(v ...byte) { -	e.out = append(e.out, v...) -} diff --git a/vendor/gopkg.in/mgo.v2/bson/json.go b/vendor/gopkg.in/mgo.v2/bson/json.go deleted file mode 100644 index 09df826..0000000 --- a/vendor/gopkg.in/mgo.v2/bson/json.go +++ /dev/null @@ -1,380 +0,0 @@ -package bson - -import ( -	"bytes" -	"encoding/base64" -	"fmt" -	"gopkg.in/mgo.v2/internal/json" -	"strconv" -	"time" -) - -// UnmarshalJSON unmarshals a JSON value that may hold non-standard -// syntax as defined in BSON's extended JSON specification. -func UnmarshalJSON(data []byte, value interface{}) error { -	d := json.NewDecoder(bytes.NewBuffer(data)) -	d.Extend(&jsonExt) -	return d.Decode(value) -} - -// MarshalJSON marshals a JSON value that may hold non-standard -// syntax as defined in BSON's extended JSON specification. -func MarshalJSON(value interface{}) ([]byte, error) { -	var buf bytes.Buffer -	e := json.NewEncoder(&buf) -	e.Extend(&jsonExt) -	err := e.Encode(value) -	if err != nil { -		return nil, err -	} -	return buf.Bytes(), nil -} - -// jdec is used internally by the JSON decoding functions -// so they may unmarshal functions without getting into endless -// recursion due to keyed objects. -func jdec(data []byte, value interface{}) error { -	d := json.NewDecoder(bytes.NewBuffer(data)) -	d.Extend(&funcExt) -	return d.Decode(value) -} - -var jsonExt json.Extension -var funcExt json.Extension - -// TODO -// - Shell regular expressions ("/regexp/opts") - -func init() { -	jsonExt.DecodeUnquotedKeys(true) -	jsonExt.DecodeTrailingCommas(true) - -	funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary") -	jsonExt.DecodeKeyed("$binary", jdecBinary) -	jsonExt.DecodeKeyed("$binaryFunc", jdecBinary) -	jsonExt.EncodeType([]byte(nil), jencBinarySlice) -	jsonExt.EncodeType(Binary{}, jencBinaryType) - -	funcExt.DecodeFunc("ISODate", "$dateFunc", "S") -	funcExt.DecodeFunc("new Date", "$dateFunc", "S") -	jsonExt.DecodeKeyed("$date", jdecDate) -	jsonExt.DecodeKeyed("$dateFunc", jdecDate) -	jsonExt.EncodeType(time.Time{}, jencDate) - -	funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i") -	jsonExt.DecodeKeyed("$timestamp", jdecTimestamp) -	jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp) - -	funcExt.DecodeConst("undefined", Undefined) - -	jsonExt.DecodeKeyed("$regex", jdecRegEx) -	jsonExt.EncodeType(RegEx{}, jencRegEx) - -	funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id") -	jsonExt.DecodeKeyed("$oid", jdecObjectId) -	jsonExt.DecodeKeyed("$oidFunc", jdecObjectId) -	jsonExt.EncodeType(ObjectId(""), jencObjectId) - -	funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id") -	jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef) - -	funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N") -	jsonExt.DecodeKeyed("$numberLong", jdecNumberLong) -	jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong) -	jsonExt.EncodeType(int64(0), jencNumberLong) -	jsonExt.EncodeType(int(0), jencInt) - -	funcExt.DecodeConst("MinKey", MinKey) -	funcExt.DecodeConst("MaxKey", MaxKey) -	jsonExt.DecodeKeyed("$minKey", jdecMinKey) -	jsonExt.DecodeKeyed("$maxKey", jdecMaxKey) -	jsonExt.EncodeType(orderKey(0), jencMinMaxKey) - -	jsonExt.DecodeKeyed("$undefined", jdecUndefined) -	jsonExt.EncodeType(Undefined, jencUndefined) - -	jsonExt.Extend(&funcExt) -} - -func fbytes(format string, args ...interface{}) []byte { -	var buf bytes.Buffer -	fmt.Fprintf(&buf, format, args...) -	return buf.Bytes() -} - -func jdecBinary(data []byte) (interface{}, error) { -	var v struct { -		Binary []byte `json:"$binary"` -		Type   string `json:"$type"` -		Func   struct { -			Binary []byte `json:"$binary"` -			Type   int64  `json:"$type"` -		} `json:"$binaryFunc"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} - -	var binData []byte -	var binKind int64 -	if v.Type == "" && v.Binary == nil { -		binData = v.Func.Binary -		binKind = v.Func.Type -	} else if v.Type == "" { -		return v.Binary, nil -	} else { -		binData = v.Binary -		binKind, err = strconv.ParseInt(v.Type, 0, 64) -		if err != nil { -			binKind = -1 -		} -	} - -	if binKind == 0 { -		return binData, nil -	} -	if binKind < 0 || binKind > 255 { -		return nil, fmt.Errorf("invalid type in binary object: %s", data) -	} - -	return Binary{Kind: byte(binKind), Data: binData}, nil -} - -func jencBinarySlice(v interface{}) ([]byte, error) { -	in := v.([]byte) -	out := make([]byte, base64.StdEncoding.EncodedLen(len(in))) -	base64.StdEncoding.Encode(out, in) -	return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil -} - -func jencBinaryType(v interface{}) ([]byte, error) { -	in := v.(Binary) -	out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data))) -	base64.StdEncoding.Encode(out, in.Data) -	return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil -} - -const jdateFormat = "2006-01-02T15:04:05.999Z" - -func jdecDate(data []byte) (interface{}, error) { -	var v struct { -		S    string `json:"$date"` -		Func struct { -			S string -		} `json:"$dateFunc"` -	} -	_ = jdec(data, &v) -	if v.S == "" { -		v.S = v.Func.S -	} -	if v.S != "" { -		for _, format := range []string{jdateFormat, "2006-01-02"} { -			t, err := time.Parse(format, v.S) -			if err == nil { -				return t, nil -			} -		} -		return nil, fmt.Errorf("cannot parse date: %q", v.S) -	} - -	var vn struct { -		Date struct { -			N int64 `json:"$numberLong,string"` -		} `json:"$date"` -		Func struct { -			S int64 -		} `json:"$dateFunc"` -	} -	err := jdec(data, &vn) -	if err != nil { -		return nil, fmt.Errorf("cannot parse date: %q", data) -	} -	n := vn.Date.N -	if n == 0 { -		n = vn.Func.S -	} -	return time.Unix(n/1000, n%1000*1e6).UTC(), nil -} - -func jencDate(v interface{}) ([]byte, error) { -	t := v.(time.Time) -	return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil -} - -func jdecTimestamp(data []byte) (interface{}, error) { -	var v struct { -		Func struct { -			T int32 `json:"t"` -			I int32 `json:"i"` -		} `json:"$timestamp"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil -} - -func jencTimestamp(v interface{}) ([]byte, error) { -	ts := uint64(v.(MongoTimestamp)) -	return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil -} - -func jdecRegEx(data []byte) (interface{}, error) { -	var v struct { -		Regex   string `json:"$regex"` -		Options string `json:"$options"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	return RegEx{v.Regex, v.Options}, nil -} - -func jencRegEx(v interface{}) ([]byte, error) { -	re := v.(RegEx) -	type regex struct { -		Regex   string `json:"$regex"` -		Options string `json:"$options"` -	} -	return json.Marshal(regex{re.Pattern, re.Options}) -} - -func jdecObjectId(data []byte) (interface{}, error) { -	var v struct { -		Id   string `json:"$oid"` -		Func struct { -			Id string -		} `json:"$oidFunc"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	if v.Id == "" { -		v.Id = v.Func.Id -	} -	return ObjectIdHex(v.Id), nil -} - -func jencObjectId(v interface{}) ([]byte, error) { -	return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil -} - -func jdecDBRef(data []byte) (interface{}, error) { -	// TODO Support unmarshaling $ref and $id into the input value. -	var v struct { -		Obj map[string]interface{} `json:"$dbrefFunc"` -	} -	// TODO Fix this. Must not be required. -	v.Obj = make(map[string]interface{}) -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	return v.Obj, nil -} - -func jdecNumberLong(data []byte) (interface{}, error) { -	var v struct { -		N    int64 `json:"$numberLong,string"` -		Func struct { -			N int64 `json:",string"` -		} `json:"$numberLongFunc"` -	} -	var vn struct { -		N    int64 `json:"$numberLong"` -		Func struct { -			N int64 -		} `json:"$numberLongFunc"` -	} -	err := jdec(data, &v) -	if err != nil { -		err = jdec(data, &vn) -		v.N = vn.N -		v.Func.N = vn.Func.N -	} -	if err != nil { -		return nil, err -	} -	if v.N != 0 { -		return v.N, nil -	} -	return v.Func.N, nil -} - -func jencNumberLong(v interface{}) ([]byte, error) { -	n := v.(int64) -	f := `{"$numberLong":"%d"}` -	if n <= 1<<53 { -		f = `{"$numberLong":%d}` -	} -	return fbytes(f, n), nil -} - -func jencInt(v interface{}) ([]byte, error) { -	n := v.(int) -	f := `{"$numberLong":"%d"}` -	if int64(n) <= 1<<53 { -		f = `%d` -	} -	return fbytes(f, n), nil -} - -func jdecMinKey(data []byte) (interface{}, error) { -	var v struct { -		N int64 `json:"$minKey"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	if v.N != 1 { -		return nil, fmt.Errorf("invalid $minKey object: %s", data) -	} -	return MinKey, nil -} - -func jdecMaxKey(data []byte) (interface{}, error) { -	var v struct { -		N int64 `json:"$maxKey"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	if v.N != 1 { -		return nil, fmt.Errorf("invalid $maxKey object: %s", data) -	} -	return MaxKey, nil -} - -func jencMinMaxKey(v interface{}) ([]byte, error) { -	switch v.(orderKey) { -	case MinKey: -		return []byte(`{"$minKey":1}`), nil -	case MaxKey: -		return []byte(`{"$maxKey":1}`), nil -	} -	panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v)) -} - -func jdecUndefined(data []byte) (interface{}, error) { -	var v struct { -		B bool `json:"$undefined"` -	} -	err := jdec(data, &v) -	if err != nil { -		return nil, err -	} -	if !v.B { -		return nil, fmt.Errorf("invalid $undefined object: %s", data) -	} -	return Undefined, nil -} - -func jencUndefined(v interface{}) ([]byte, error) { -	return []byte(`{"$undefined":true}`), nil -} diff --git a/vendor/gopkg.in/mgo.v2/bulk.go b/vendor/gopkg.in/mgo.v2/bulk.go deleted file mode 100644 index 072a520..0000000 --- a/vendor/gopkg.in/mgo.v2/bulk.go +++ /dev/null @@ -1,351 +0,0 @@ -package mgo - -import ( -	"bytes" -	"sort" - -	"gopkg.in/mgo.v2/bson" -) - -// Bulk represents an operation that can be prepared with several -// orthogonal changes before being delivered to the server. -// -// MongoDB servers older than version 2.6 do not have proper support for bulk -// operations, so the driver attempts to map its API as much as possible into -// the functionality that works. In particular, in those releases updates and -// removals are sent individually, and inserts are sent in bulk but have -// suboptimal error reporting compared to more recent versions of the server. -// See the documentation of BulkErrorCase for details on that. -// -// Relevant documentation: -// -//   http://blog.mongodb.org/post/84922794768/mongodbs-new-bulk-api -// -type Bulk struct { -	c       *Collection -	opcount int -	actions []bulkAction -	ordered bool -} - -type bulkOp int - -const ( -	bulkInsert bulkOp = iota + 1 -	bulkUpdate -	bulkUpdateAll -	bulkRemove -) - -type bulkAction struct { -	op   bulkOp -	docs []interface{} -	idxs []int -} - -type bulkUpdateOp []interface{} -type bulkDeleteOp []interface{} - -// BulkResult holds the results for a bulk operation. -type BulkResult struct { -	Matched  int -	Modified int // Available only for MongoDB 2.6+ - -	// Be conservative while we understand exactly how to report these -	// results in a useful and convenient way, and also how to emulate -	// them with prior servers. -	private bool -} - -// BulkError holds an error returned from running a Bulk operation. -// Individual errors may be obtained and inspected via the Cases method. -type BulkError struct { -	ecases []BulkErrorCase -} - -func (e *BulkError) Error() string { -	if len(e.ecases) == 0 { -		return "invalid BulkError instance: no errors" -	} -	if len(e.ecases) == 1 { -		return e.ecases[0].Err.Error() -	} -	msgs := make([]string, 0, len(e.ecases)) -	seen := make(map[string]bool) -	for _, ecase := range e.ecases { -		msg := ecase.Err.Error() -		if !seen[msg] { -			seen[msg] = true -			msgs = append(msgs, msg) -		} -	} -	if len(msgs) == 1 { -		return msgs[0] -	} -	var buf bytes.Buffer -	buf.WriteString("multiple errors in bulk operation:\n") -	for _, msg := range msgs { -		buf.WriteString("  - ") -		buf.WriteString(msg) -		buf.WriteByte('\n') -	} -	return buf.String() -} - -type bulkErrorCases []BulkErrorCase - -func (slice bulkErrorCases) Len() int           { return len(slice) } -func (slice bulkErrorCases) Less(i, j int) bool { return slice[i].Index < slice[j].Index } -func (slice bulkErrorCases) Swap(i, j int)      { slice[i], slice[j] = slice[j], slice[i] } - -// BulkErrorCase holds an individual error found while attempting a single change -// within a bulk operation, and the position in which it was enqueued. -// -// MongoDB servers older than version 2.6 do not have proper support for bulk -// operations, so the driver attempts to map its API as much as possible into -// the functionality that works. In particular, only the last error is reported -// for bulk inserts and without any positional information, so the Index -// field is set to -1 in these cases. -type BulkErrorCase struct { -	Index int // Position of operation that failed, or -1 if unknown. -	Err   error -} - -// Cases returns all individual errors found while attempting the requested changes. -// -// See the documentation of BulkErrorCase for limitations in older MongoDB releases. -func (e *BulkError) Cases() []BulkErrorCase { -	return e.ecases -} - -// Bulk returns a value to prepare the execution of a bulk operation. -func (c *Collection) Bulk() *Bulk { -	return &Bulk{c: c, ordered: true} -} - -// Unordered puts the bulk operation in unordered mode. -// -// In unordered mode the indvidual operations may be sent -// out of order, which means latter operations may proceed -// even if prior ones have failed. -func (b *Bulk) Unordered() { -	b.ordered = false -} - -func (b *Bulk) action(op bulkOp, opcount int) *bulkAction { -	var action *bulkAction -	if len(b.actions) > 0 && b.actions[len(b.actions)-1].op == op { -		action = &b.actions[len(b.actions)-1] -	} else if !b.ordered { -		for i := range b.actions { -			if b.actions[i].op == op { -				action = &b.actions[i] -				break -			} -		} -	} -	if action == nil { -		b.actions = append(b.actions, bulkAction{op: op}) -		action = &b.actions[len(b.actions)-1] -	} -	for i := 0; i < opcount; i++ { -		action.idxs = append(action.idxs, b.opcount) -		b.opcount++ -	} -	return action -} - -// Insert queues up the provided documents for insertion. -func (b *Bulk) Insert(docs ...interface{}) { -	action := b.action(bulkInsert, len(docs)) -	action.docs = append(action.docs, docs...) -} - -// Remove queues up the provided selectors for removing matching documents. -// Each selector will remove only a single matching document. -func (b *Bulk) Remove(selectors ...interface{}) { -	action := b.action(bulkRemove, len(selectors)) -	for _, selector := range selectors { -		if selector == nil { -			selector = bson.D{} -		} -		action.docs = append(action.docs, &deleteOp{ -			Collection: b.c.FullName, -			Selector:   selector, -			Flags:      1, -			Limit:      1, -		}) -	} -} - -// RemoveAll queues up the provided selectors for removing all matching documents. -// Each selector will remove all matching documents. -func (b *Bulk) RemoveAll(selectors ...interface{}) { -	action := b.action(bulkRemove, len(selectors)) -	for _, selector := range selectors { -		if selector == nil { -			selector = bson.D{} -		} -		action.docs = append(action.docs, &deleteOp{ -			Collection: b.c.FullName, -			Selector:   selector, -			Flags:      0, -			Limit:      0, -		}) -	} -} - -// Update queues up the provided pairs of updating instructions. -// The first element of each pair selects which documents must be -// updated, and the second element defines how to update it. -// Each pair matches exactly one document for updating at most. -func (b *Bulk) Update(pairs ...interface{}) { -	if len(pairs)%2 != 0 { -		panic("Bulk.Update requires an even number of parameters") -	} -	action := b.action(bulkUpdate, len(pairs)/2) -	for i := 0; i < len(pairs); i += 2 { -		selector := pairs[i] -		if selector == nil { -			selector = bson.D{} -		} -		action.docs = append(action.docs, &updateOp{ -			Collection: b.c.FullName, -			Selector:   selector, -			Update:     pairs[i+1], -		}) -	} -} - -// UpdateAll queues up the provided pairs of updating instructions. -// The first element of each pair selects which documents must be -// updated, and the second element defines how to update it. -// Each pair updates all documents matching the selector. -func (b *Bulk) UpdateAll(pairs ...interface{}) { -	if len(pairs)%2 != 0 { -		panic("Bulk.UpdateAll requires an even number of parameters") -	} -	action := b.action(bulkUpdate, len(pairs)/2) -	for i := 0; i < len(pairs); i += 2 { -		selector := pairs[i] -		if selector == nil { -			selector = bson.D{} -		} -		action.docs = append(action.docs, &updateOp{ -			Collection: b.c.FullName, -			Selector:   selector, -			Update:     pairs[i+1], -			Flags:      2, -			Multi:      true, -		}) -	} -} - -// Upsert queues up the provided pairs of upserting instructions. -// The first element of each pair selects which documents must be -// updated, and the second element defines how to update it. -// Each pair matches exactly one document for updating at most. -func (b *Bulk) Upsert(pairs ...interface{}) { -	if len(pairs)%2 != 0 { -		panic("Bulk.Update requires an even number of parameters") -	} -	action := b.action(bulkUpdate, len(pairs)/2) -	for i := 0; i < len(pairs); i += 2 { -		selector := pairs[i] -		if selector == nil { -			selector = bson.D{} -		} -		action.docs = append(action.docs, &updateOp{ -			Collection: b.c.FullName, -			Selector:   selector, -			Update:     pairs[i+1], -			Flags:      1, -			Upsert:     true, -		}) -	} -} - -// Run runs all the operations queued up. -// -// If an error is reported on an unordered bulk operation, the error value may -// be an aggregation of all issues observed. As an exception to that, Insert -// operations running on MongoDB versions prior to 2.6 will report the last -// error only due to a limitation in the wire protocol. -func (b *Bulk) Run() (*BulkResult, error) { -	var result BulkResult -	var berr BulkError -	var failed bool -	for i := range b.actions { -		action := &b.actions[i] -		var ok bool -		switch action.op { -		case bulkInsert: -			ok = b.runInsert(action, &result, &berr) -		case bulkUpdate: -			ok = b.runUpdate(action, &result, &berr) -		case bulkRemove: -			ok = b.runRemove(action, &result, &berr) -		default: -			panic("unknown bulk operation") -		} -		if !ok { -			failed = true -			if b.ordered { -				break -			} -		} -	} -	if failed { -		sort.Sort(bulkErrorCases(berr.ecases)) -		return nil, &berr -	} -	return &result, nil -} - -func (b *Bulk) runInsert(action *bulkAction, result *BulkResult, berr *BulkError) bool { -	op := &insertOp{b.c.FullName, action.docs, 0} -	if !b.ordered { -		op.flags = 1 // ContinueOnError -	} -	lerr, err := b.c.writeOp(op, b.ordered) -	return b.checkSuccess(action, berr, lerr, err) -} - -func (b *Bulk) runUpdate(action *bulkAction, result *BulkResult, berr *BulkError) bool { -	lerr, err := b.c.writeOp(bulkUpdateOp(action.docs), b.ordered) -	if lerr != nil { -		result.Matched += lerr.N -		result.Modified += lerr.modified -	} -	return b.checkSuccess(action, berr, lerr, err) -} - -func (b *Bulk) runRemove(action *bulkAction, result *BulkResult, berr *BulkError) bool { -	lerr, err := b.c.writeOp(bulkDeleteOp(action.docs), b.ordered) -	if lerr != nil { -		result.Matched += lerr.N -		result.Modified += lerr.modified -	} -	return b.checkSuccess(action, berr, lerr, err) -} - -func (b *Bulk) checkSuccess(action *bulkAction, berr *BulkError, lerr *LastError, err error) bool { -	if lerr != nil && len(lerr.ecases) > 0 { -		for i := 0; i < len(lerr.ecases); i++ { -			// Map back from the local error index into the visible one. -			ecase := lerr.ecases[i] -			idx := ecase.Index -			if idx >= 0 { -				idx = action.idxs[idx] -			} -			berr.ecases = append(berr.ecases, BulkErrorCase{idx, ecase.Err}) -		} -		return false -	} else if err != nil { -		for i := 0; i < len(action.idxs); i++ { -			berr.ecases = append(berr.ecases, BulkErrorCase{action.idxs[i], err}) -		} -		return false -	} -	return true -} diff --git a/vendor/gopkg.in/mgo.v2/cluster.go b/vendor/gopkg.in/mgo.v2/cluster.go deleted file mode 100644 index c3bf8b0..0000000 --- a/vendor/gopkg.in/mgo.v2/cluster.go +++ /dev/null @@ -1,682 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"errors" -	"fmt" -	"net" -	"strconv" -	"strings" -	"sync" -	"time" - -	"gopkg.in/mgo.v2/bson" -) - -// --------------------------------------------------------------------------- -// Mongo cluster encapsulation. -// -// A cluster enables the communication with one or more servers participating -// in a mongo cluster.  This works with individual servers, a replica set, -// a replica pair, one or multiple mongos routers, etc. - -type mongoCluster struct { -	sync.RWMutex -	serverSynced sync.Cond -	userSeeds    []string -	dynaSeeds    []string -	servers      mongoServers -	masters      mongoServers -	references   int -	syncing      bool -	direct       bool -	failFast     bool -	syncCount    uint -	setName      string -	cachedIndex  map[string]bool -	sync         chan bool -	dial         dialer -} - -func newCluster(userSeeds []string, direct, failFast bool, dial dialer, setName string) *mongoCluster { -	cluster := &mongoCluster{ -		userSeeds:  userSeeds, -		references: 1, -		direct:     direct, -		failFast:   failFast, -		dial:       dial, -		setName:    setName, -	} -	cluster.serverSynced.L = cluster.RWMutex.RLocker() -	cluster.sync = make(chan bool, 1) -	stats.cluster(+1) -	go cluster.syncServersLoop() -	return cluster -} - -// Acquire increases the reference count for the cluster. -func (cluster *mongoCluster) Acquire() { -	cluster.Lock() -	cluster.references++ -	debugf("Cluster %p acquired (refs=%d)", cluster, cluster.references) -	cluster.Unlock() -} - -// Release decreases the reference count for the cluster. Once -// it reaches zero, all servers will be closed. -func (cluster *mongoCluster) Release() { -	cluster.Lock() -	if cluster.references == 0 { -		panic("cluster.Release() with references == 0") -	} -	cluster.references-- -	debugf("Cluster %p released (refs=%d)", cluster, cluster.references) -	if cluster.references == 0 { -		for _, server := range cluster.servers.Slice() { -			server.Close() -		} -		// Wake up the sync loop so it can die. -		cluster.syncServers() -		stats.cluster(-1) -	} -	cluster.Unlock() -} - -func (cluster *mongoCluster) LiveServers() (servers []string) { -	cluster.RLock() -	for _, serv := range cluster.servers.Slice() { -		servers = append(servers, serv.Addr) -	} -	cluster.RUnlock() -	return servers -} - -func (cluster *mongoCluster) removeServer(server *mongoServer) { -	cluster.Lock() -	cluster.masters.Remove(server) -	other := cluster.servers.Remove(server) -	cluster.Unlock() -	if other != nil { -		other.Close() -		log("Removed server ", server.Addr, " from cluster.") -	} -	server.Close() -} - -type isMasterResult struct { -	IsMaster       bool -	Secondary      bool -	Primary        string -	Hosts          []string -	Passives       []string -	Tags           bson.D -	Msg            string -	SetName        string `bson:"setName"` -	MaxWireVersion int    `bson:"maxWireVersion"` -} - -func (cluster *mongoCluster) isMaster(socket *mongoSocket, result *isMasterResult) error { -	// Monotonic let's it talk to a slave and still hold the socket. -	session := newSession(Monotonic, cluster, 10*time.Second) -	session.setSocket(socket) -	err := session.Run("ismaster", result) -	session.Close() -	return err -} - -type possibleTimeout interface { -	Timeout() bool -} - -var syncSocketTimeout = 5 * time.Second - -func (cluster *mongoCluster) syncServer(server *mongoServer) (info *mongoServerInfo, hosts []string, err error) { -	var syncTimeout time.Duration -	if raceDetector { -		// This variable is only ever touched by tests. -		globalMutex.Lock() -		syncTimeout = syncSocketTimeout -		globalMutex.Unlock() -	} else { -		syncTimeout = syncSocketTimeout -	} - -	addr := server.Addr -	log("SYNC Processing ", addr, "...") - -	// Retry a few times to avoid knocking a server down for a hiccup. -	var result isMasterResult -	var tryerr error -	for retry := 0; ; retry++ { -		if retry == 3 || retry == 1 && cluster.failFast { -			return nil, nil, tryerr -		} -		if retry > 0 { -			// Don't abuse the server needlessly if there's something actually wrong. -			if err, ok := tryerr.(possibleTimeout); ok && err.Timeout() { -				// Give a chance for waiters to timeout as well. -				cluster.serverSynced.Broadcast() -			} -			time.Sleep(syncShortDelay) -		} - -		// It's not clear what would be a good timeout here. Is it -		// better to wait longer or to retry? -		socket, _, err := server.AcquireSocket(0, syncTimeout) -		if err != nil { -			tryerr = err -			logf("SYNC Failed to get socket to %s: %v", addr, err) -			continue -		} -		err = cluster.isMaster(socket, &result) -		socket.Release() -		if err != nil { -			tryerr = err -			logf("SYNC Command 'ismaster' to %s failed: %v", addr, err) -			continue -		} -		debugf("SYNC Result of 'ismaster' from %s: %#v", addr, result) -		break -	} - -	if cluster.setName != "" && result.SetName != cluster.setName { -		logf("SYNC Server %s is not a member of replica set %q", addr, cluster.setName) -		return nil, nil, fmt.Errorf("server %s is not a member of replica set %q", addr, cluster.setName) -	} - -	if result.IsMaster { -		debugf("SYNC %s is a master.", addr) -		if !server.info.Master { -			// Made an incorrect assumption above, so fix stats. -			stats.conn(-1, false) -			stats.conn(+1, true) -		} -	} else if result.Secondary { -		debugf("SYNC %s is a slave.", addr) -	} else if cluster.direct { -		logf("SYNC %s in unknown state. Pretending it's a slave due to direct connection.", addr) -	} else { -		logf("SYNC %s is neither a master nor a slave.", addr) -		// Let stats track it as whatever was known before. -		return nil, nil, errors.New(addr + " is not a master nor slave") -	} - -	info = &mongoServerInfo{ -		Master:         result.IsMaster, -		Mongos:         result.Msg == "isdbgrid", -		Tags:           result.Tags, -		SetName:        result.SetName, -		MaxWireVersion: result.MaxWireVersion, -	} - -	hosts = make([]string, 0, 1+len(result.Hosts)+len(result.Passives)) -	if result.Primary != "" { -		// First in the list to speed up master discovery. -		hosts = append(hosts, result.Primary) -	} -	hosts = append(hosts, result.Hosts...) -	hosts = append(hosts, result.Passives...) - -	debugf("SYNC %s knows about the following peers: %#v", addr, hosts) -	return info, hosts, nil -} - -type syncKind bool - -const ( -	completeSync syncKind = true -	partialSync  syncKind = false -) - -func (cluster *mongoCluster) addServer(server *mongoServer, info *mongoServerInfo, syncKind syncKind) { -	cluster.Lock() -	current := cluster.servers.Search(server.ResolvedAddr) -	if current == nil { -		if syncKind == partialSync { -			cluster.Unlock() -			server.Close() -			log("SYNC Discarding unknown server ", server.Addr, " due to partial sync.") -			return -		} -		cluster.servers.Add(server) -		if info.Master { -			cluster.masters.Add(server) -			log("SYNC Adding ", server.Addr, " to cluster as a master.") -		} else { -			log("SYNC Adding ", server.Addr, " to cluster as a slave.") -		} -	} else { -		if server != current { -			panic("addServer attempting to add duplicated server") -		} -		if server.Info().Master != info.Master { -			if info.Master { -				log("SYNC Server ", server.Addr, " is now a master.") -				cluster.masters.Add(server) -			} else { -				log("SYNC Server ", server.Addr, " is now a slave.") -				cluster.masters.Remove(server) -			} -		} -	} -	server.SetInfo(info) -	debugf("SYNC Broadcasting availability of server %s", server.Addr) -	cluster.serverSynced.Broadcast() -	cluster.Unlock() -} - -func (cluster *mongoCluster) getKnownAddrs() []string { -	cluster.RLock() -	max := len(cluster.userSeeds) + len(cluster.dynaSeeds) + cluster.servers.Len() -	seen := make(map[string]bool, max) -	known := make([]string, 0, max) - -	add := func(addr string) { -		if _, found := seen[addr]; !found { -			seen[addr] = true -			known = append(known, addr) -		} -	} - -	for _, addr := range cluster.userSeeds { -		add(addr) -	} -	for _, addr := range cluster.dynaSeeds { -		add(addr) -	} -	for _, serv := range cluster.servers.Slice() { -		add(serv.Addr) -	} -	cluster.RUnlock() - -	return known -} - -// syncServers injects a value into the cluster.sync channel to force -// an iteration of the syncServersLoop function. -func (cluster *mongoCluster) syncServers() { -	select { -	case cluster.sync <- true: -	default: -	} -} - -// How long to wait for a checkup of the cluster topology if nothing -// else kicks a synchronization before that. -const syncServersDelay = 30 * time.Second -const syncShortDelay = 500 * time.Millisecond - -// syncServersLoop loops while the cluster is alive to keep its idea of -// the server topology up-to-date. It must be called just once from -// newCluster.  The loop iterates once syncServersDelay has passed, or -// if somebody injects a value into the cluster.sync channel to force a -// synchronization.  A loop iteration will contact all servers in -// parallel, ask them about known peers and their own role within the -// cluster, and then attempt to do the same with all the peers -// retrieved. -func (cluster *mongoCluster) syncServersLoop() { -	for { -		debugf("SYNC Cluster %p is starting a sync loop iteration.", cluster) - -		cluster.Lock() -		if cluster.references == 0 { -			cluster.Unlock() -			break -		} -		cluster.references++ // Keep alive while syncing. -		direct := cluster.direct -		cluster.Unlock() - -		cluster.syncServersIteration(direct) - -		// We just synchronized, so consume any outstanding requests. -		select { -		case <-cluster.sync: -		default: -		} - -		cluster.Release() - -		// Hold off before allowing another sync. No point in -		// burning CPU looking for down servers. -		if !cluster.failFast { -			time.Sleep(syncShortDelay) -		} - -		cluster.Lock() -		if cluster.references == 0 { -			cluster.Unlock() -			break -		} -		cluster.syncCount++ -		// Poke all waiters so they have a chance to timeout or -		// restart syncing if they wish to. -		cluster.serverSynced.Broadcast() -		// Check if we have to restart immediately either way. -		restart := !direct && cluster.masters.Empty() || cluster.servers.Empty() -		cluster.Unlock() - -		if restart { -			log("SYNC No masters found. Will synchronize again.") -			time.Sleep(syncShortDelay) -			continue -		} - -		debugf("SYNC Cluster %p waiting for next requested or scheduled sync.", cluster) - -		// Hold off until somebody explicitly requests a synchronization -		// or it's time to check for a cluster topology change again. -		select { -		case <-cluster.sync: -		case <-time.After(syncServersDelay): -		} -	} -	debugf("SYNC Cluster %p is stopping its sync loop.", cluster) -} - -func (cluster *mongoCluster) server(addr string, tcpaddr *net.TCPAddr) *mongoServer { -	cluster.RLock() -	server := cluster.servers.Search(tcpaddr.String()) -	cluster.RUnlock() -	if server != nil { -		return server -	} -	return newServer(addr, tcpaddr, cluster.sync, cluster.dial) -} - -func resolveAddr(addr string) (*net.TCPAddr, error) { -	// Simple cases that do not need actual resolution. Works with IPv4 and v6. -	if host, port, err := net.SplitHostPort(addr); err == nil { -		if port, _ := strconv.Atoi(port); port > 0 { -			zone := "" -			if i := strings.LastIndex(host, "%"); i >= 0 { -				zone = host[i+1:] -				host = host[:i] -			} -			ip := net.ParseIP(host) -			if ip != nil { -				return &net.TCPAddr{IP: ip, Port: port, Zone: zone}, nil -			} -		} -	} - -	// Attempt to resolve IPv4 and v6 concurrently. -	addrChan := make(chan *net.TCPAddr, 2) -	for _, network := range []string{"udp4", "udp6"} { -		network := network -		go func() { -			// The unfortunate UDP dialing hack allows having a timeout on address resolution. -			conn, err := net.DialTimeout(network, addr, 10*time.Second) -			if err != nil { -				addrChan <- nil -			} else { -				addrChan <- (*net.TCPAddr)(conn.RemoteAddr().(*net.UDPAddr)) -				conn.Close() -			} -		}() -	} - -	// Wait for the result of IPv4 and v6 resolution. Use IPv4 if available. -	tcpaddr := <-addrChan -	if tcpaddr == nil || len(tcpaddr.IP) != 4 { -		var timeout <-chan time.Time -		if tcpaddr != nil { -			// Don't wait too long if an IPv6 address is known. -			timeout = time.After(50 * time.Millisecond) -		} -		select { -		case <-timeout: -		case tcpaddr2 := <-addrChan: -			if tcpaddr == nil || tcpaddr2 != nil { -				// It's an IPv4 address or the only known address. Use it. -				tcpaddr = tcpaddr2 -			} -		} -	} - -	if tcpaddr == nil { -		log("SYNC Failed to resolve server address: ", addr) -		return nil, errors.New("failed to resolve server address: " + addr) -	} -	if tcpaddr.String() != addr { -		debug("SYNC Address ", addr, " resolved as ", tcpaddr.String()) -	} -	return tcpaddr, nil -} - -type pendingAdd struct { -	server *mongoServer -	info   *mongoServerInfo -} - -func (cluster *mongoCluster) syncServersIteration(direct bool) { -	log("SYNC Starting full topology synchronization...") - -	var wg sync.WaitGroup -	var m sync.Mutex -	notYetAdded := make(map[string]pendingAdd) -	addIfFound := make(map[string]bool) -	seen := make(map[string]bool) -	syncKind := partialSync - -	var spawnSync func(addr string, byMaster bool) -	spawnSync = func(addr string, byMaster bool) { -		wg.Add(1) -		go func() { -			defer wg.Done() - -			tcpaddr, err := resolveAddr(addr) -			if err != nil { -				log("SYNC Failed to start sync of ", addr, ": ", err.Error()) -				return -			} -			resolvedAddr := tcpaddr.String() - -			m.Lock() -			if byMaster { -				if pending, ok := notYetAdded[resolvedAddr]; ok { -					delete(notYetAdded, resolvedAddr) -					m.Unlock() -					cluster.addServer(pending.server, pending.info, completeSync) -					return -				} -				addIfFound[resolvedAddr] = true -			} -			if seen[resolvedAddr] { -				m.Unlock() -				return -			} -			seen[resolvedAddr] = true -			m.Unlock() - -			server := cluster.server(addr, tcpaddr) -			info, hosts, err := cluster.syncServer(server) -			if err != nil { -				cluster.removeServer(server) -				return -			} - -			m.Lock() -			add := direct || info.Master || addIfFound[resolvedAddr] -			if add { -				syncKind = completeSync -			} else { -				notYetAdded[resolvedAddr] = pendingAdd{server, info} -			} -			m.Unlock() -			if add { -				cluster.addServer(server, info, completeSync) -			} -			if !direct { -				for _, addr := range hosts { -					spawnSync(addr, info.Master) -				} -			} -		}() -	} - -	knownAddrs := cluster.getKnownAddrs() -	for _, addr := range knownAddrs { -		spawnSync(addr, false) -	} -	wg.Wait() - -	if syncKind == completeSync { -		logf("SYNC Synchronization was complete (got data from primary).") -		for _, pending := range notYetAdded { -			cluster.removeServer(pending.server) -		} -	} else { -		logf("SYNC Synchronization was partial (cannot talk to primary).") -		for _, pending := range notYetAdded { -			cluster.addServer(pending.server, pending.info, partialSync) -		} -	} - -	cluster.Lock() -	mastersLen := cluster.masters.Len() -	logf("SYNC Synchronization completed: %d master(s) and %d slave(s) alive.", mastersLen, cluster.servers.Len()-mastersLen) - -	// Update dynamic seeds, but only if we have any good servers. Otherwise, -	// leave them alone for better chances of a successful sync in the future. -	if syncKind == completeSync { -		dynaSeeds := make([]string, cluster.servers.Len()) -		for i, server := range cluster.servers.Slice() { -			dynaSeeds[i] = server.Addr -		} -		cluster.dynaSeeds = dynaSeeds -		debugf("SYNC New dynamic seeds: %#v\n", dynaSeeds) -	} -	cluster.Unlock() -} - -// AcquireSocket returns a socket to a server in the cluster.  If slaveOk is -// true, it will attempt to return a socket to a slave server.  If it is -// false, the socket will necessarily be to a master server. -func (cluster *mongoCluster) AcquireSocket(mode Mode, slaveOk bool, syncTimeout time.Duration, socketTimeout time.Duration, serverTags []bson.D, poolLimit int) (s *mongoSocket, err error) { -	var started time.Time -	var syncCount uint -	warnedLimit := false -	for { -		cluster.RLock() -		for { -			mastersLen := cluster.masters.Len() -			slavesLen := cluster.servers.Len() - mastersLen -			debugf("Cluster has %d known masters and %d known slaves.", mastersLen, slavesLen) -			if mastersLen > 0 && !(slaveOk && mode == Secondary) || slavesLen > 0 && slaveOk { -				break -			} -			if mastersLen > 0 && mode == Secondary && cluster.masters.HasMongos() { -				break -			} -			if started.IsZero() { -				// Initialize after fast path above. -				started = time.Now() -				syncCount = cluster.syncCount -			} else if syncTimeout != 0 && started.Before(time.Now().Add(-syncTimeout)) || cluster.failFast && cluster.syncCount != syncCount { -				cluster.RUnlock() -				return nil, errors.New("no reachable servers") -			} -			log("Waiting for servers to synchronize...") -			cluster.syncServers() - -			// Remember: this will release and reacquire the lock. -			cluster.serverSynced.Wait() -		} - -		var server *mongoServer -		if slaveOk { -			server = cluster.servers.BestFit(mode, serverTags) -		} else { -			server = cluster.masters.BestFit(mode, nil) -		} -		cluster.RUnlock() - -		if server == nil { -			// Must have failed the requested tags. Sleep to avoid spinning. -			time.Sleep(1e8) -			continue -		} - -		s, abended, err := server.AcquireSocket(poolLimit, socketTimeout) -		if err == errPoolLimit { -			if !warnedLimit { -				warnedLimit = true -				log("WARNING: Per-server connection limit reached.") -			} -			time.Sleep(100 * time.Millisecond) -			continue -		} -		if err != nil { -			cluster.removeServer(server) -			cluster.syncServers() -			continue -		} -		if abended && !slaveOk { -			var result isMasterResult -			err := cluster.isMaster(s, &result) -			if err != nil || !result.IsMaster { -				logf("Cannot confirm server %s as master (%v)", server.Addr, err) -				s.Release() -				cluster.syncServers() -				time.Sleep(100 * time.Millisecond) -				continue -			} -		} -		return s, nil -	} -	panic("unreached") -} - -func (cluster *mongoCluster) CacheIndex(cacheKey string, exists bool) { -	cluster.Lock() -	if cluster.cachedIndex == nil { -		cluster.cachedIndex = make(map[string]bool) -	} -	if exists { -		cluster.cachedIndex[cacheKey] = true -	} else { -		delete(cluster.cachedIndex, cacheKey) -	} -	cluster.Unlock() -} - -func (cluster *mongoCluster) HasCachedIndex(cacheKey string) (result bool) { -	cluster.RLock() -	if cluster.cachedIndex != nil { -		result = cluster.cachedIndex[cacheKey] -	} -	cluster.RUnlock() -	return -} - -func (cluster *mongoCluster) ResetIndexCache() { -	cluster.Lock() -	cluster.cachedIndex = make(map[string]bool) -	cluster.Unlock() -} diff --git a/vendor/gopkg.in/mgo.v2/doc.go b/vendor/gopkg.in/mgo.v2/doc.go deleted file mode 100644 index 859fd9b..0000000 --- a/vendor/gopkg.in/mgo.v2/doc.go +++ /dev/null @@ -1,31 +0,0 @@ -// Package mgo offers a rich MongoDB driver for Go. -// -// Details about the mgo project (pronounced as "mango") are found -// in its web page: -// -//     http://labix.org/mgo -// -// Usage of the driver revolves around the concept of sessions.  To -// get started, obtain a session using the Dial function: -// -//     session, err := mgo.Dial(url) -// -// This will establish one or more connections with the cluster of -// servers defined by the url parameter.  From then on, the cluster -// may be queried with multiple consistency rules (see SetMode) and -// documents retrieved with statements such as: -// -//     c := session.DB(database).C(collection) -//     err := c.Find(query).One(&result) -// -// New sessions are typically created by calling session.Copy on the -// initial session obtained at dial time. These new sessions will share -// the same cluster information and connection pool, and may be easily -// handed into other methods and functions for organizing logic. -// Every session created must have its Close method called at the end -// of its life time, so its resources may be put back in the pool or -// collected, depending on the case. -// -// For more details, see the documentation for the types and methods. -// -package mgo diff --git a/vendor/gopkg.in/mgo.v2/gridfs.go b/vendor/gopkg.in/mgo.v2/gridfs.go deleted file mode 100644 index 4214720..0000000 --- a/vendor/gopkg.in/mgo.v2/gridfs.go +++ /dev/null @@ -1,761 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"crypto/md5" -	"encoding/hex" -	"errors" -	"hash" -	"io" -	"os" -	"sync" -	"time" - -	"gopkg.in/mgo.v2/bson" -) - -type GridFS struct { -	Files  *Collection -	Chunks *Collection -} - -type gfsFileMode int - -const ( -	gfsClosed  gfsFileMode = 0 -	gfsReading gfsFileMode = 1 -	gfsWriting gfsFileMode = 2 -) - -type GridFile struct { -	m    sync.Mutex -	c    sync.Cond -	gfs  *GridFS -	mode gfsFileMode -	err  error - -	chunk  int -	offset int64 - -	wpending int -	wbuf     []byte -	wsum     hash.Hash - -	rbuf   []byte -	rcache *gfsCachedChunk - -	doc gfsFile -} - -type gfsFile struct { -	Id          interface{} "_id" -	ChunkSize   int         "chunkSize" -	UploadDate  time.Time   "uploadDate" -	Length      int64       ",minsize" -	MD5         string -	Filename    string    ",omitempty" -	ContentType string    "contentType,omitempty" -	Metadata    *bson.Raw ",omitempty" -} - -type gfsChunk struct { -	Id      interface{} "_id" -	FilesId interface{} "files_id" -	N       int -	Data    []byte -} - -type gfsCachedChunk struct { -	wait sync.Mutex -	n    int -	data []byte -	err  error -} - -func newGridFS(db *Database, prefix string) *GridFS { -	return &GridFS{db.C(prefix + ".files"), db.C(prefix + ".chunks")} -} - -func (gfs *GridFS) newFile() *GridFile { -	file := &GridFile{gfs: gfs} -	file.c.L = &file.m -	//runtime.SetFinalizer(file, finalizeFile) -	return file -} - -func finalizeFile(file *GridFile) { -	file.Close() -} - -// Create creates a new file with the provided name in the GridFS.  If the file -// name already exists, a new version will be inserted with an up-to-date -// uploadDate that will cause it to be atomically visible to the Open and -// OpenId methods.  If the file name is not important, an empty name may be -// provided and the file Id used instead. -// -// It's important to Close files whether they are being written to -// or read from, and to check the err result to ensure the operation -// completed successfully. -// -// A simple example inserting a new file: -// -//     func check(err error) { -//         if err != nil { -//             panic(err.String()) -//         } -//     } -//     file, err := db.GridFS("fs").Create("myfile.txt") -//     check(err) -//     n, err := file.Write([]byte("Hello world!")) -//     check(err) -//     err = file.Close() -//     check(err) -//     fmt.Printf("%d bytes written\n", n) -// -// The io.Writer interface is implemented by *GridFile and may be used to -// help on the file creation.  For example: -// -//     file, err := db.GridFS("fs").Create("myfile.txt") -//     check(err) -//     messages, err := os.Open("/var/log/messages") -//     check(err) -//     defer messages.Close() -//     err = io.Copy(file, messages) -//     check(err) -//     err = file.Close() -//     check(err) -// -func (gfs *GridFS) Create(name string) (file *GridFile, err error) { -	file = gfs.newFile() -	file.mode = gfsWriting -	file.wsum = md5.New() -	file.doc = gfsFile{Id: bson.NewObjectId(), ChunkSize: 255 * 1024, Filename: name} -	return -} - -// OpenId returns the file with the provided id, for reading. -// If the file isn't found, err will be set to mgo.ErrNotFound. -// -// It's important to Close files whether they are being written to -// or read from, and to check the err result to ensure the operation -// completed successfully. -// -// The following example will print the first 8192 bytes from the file: -// -//     func check(err error) { -//         if err != nil { -//             panic(err.String()) -//         } -//     } -//     file, err := db.GridFS("fs").OpenId(objid) -//     check(err) -//     b := make([]byte, 8192) -//     n, err := file.Read(b) -//     check(err) -//     fmt.Println(string(b)) -//     check(err) -//     err = file.Close() -//     check(err) -//     fmt.Printf("%d bytes read\n", n) -// -// The io.Reader interface is implemented by *GridFile and may be used to -// deal with it.  As an example, the following snippet will dump the whole -// file into the standard output: -// -//     file, err := db.GridFS("fs").OpenId(objid) -//     check(err) -//     err = io.Copy(os.Stdout, file) -//     check(err) -//     err = file.Close() -//     check(err) -// -func (gfs *GridFS) OpenId(id interface{}) (file *GridFile, err error) { -	var doc gfsFile -	err = gfs.Files.Find(bson.M{"_id": id}).One(&doc) -	if err != nil { -		return -	} -	file = gfs.newFile() -	file.mode = gfsReading -	file.doc = doc -	return -} - -// Open returns the most recently uploaded file with the provided -// name, for reading. If the file isn't found, err will be set -// to mgo.ErrNotFound. -// -// It's important to Close files whether they are being written to -// or read from, and to check the err result to ensure the operation -// completed successfully. -// -// The following example will print the first 8192 bytes from the file: -// -//     file, err := db.GridFS("fs").Open("myfile.txt") -//     check(err) -//     b := make([]byte, 8192) -//     n, err := file.Read(b) -//     check(err) -//     fmt.Println(string(b)) -//     check(err) -//     err = file.Close() -//     check(err) -//     fmt.Printf("%d bytes read\n", n) -// -// The io.Reader interface is implemented by *GridFile and may be used to -// deal with it.  As an example, the following snippet will dump the whole -// file into the standard output: -// -//     file, err := db.GridFS("fs").Open("myfile.txt") -//     check(err) -//     err = io.Copy(os.Stdout, file) -//     check(err) -//     err = file.Close() -//     check(err) -// -func (gfs *GridFS) Open(name string) (file *GridFile, err error) { -	var doc gfsFile -	err = gfs.Files.Find(bson.M{"filename": name}).Sort("-uploadDate").One(&doc) -	if err != nil { -		return -	} -	file = gfs.newFile() -	file.mode = gfsReading -	file.doc = doc -	return -} - -// OpenNext opens the next file from iter for reading, sets *file to it, -// and returns true on the success case. If no more documents are available -// on iter or an error occurred, *file is set to nil and the result is false. -// Errors will be available via iter.Err(). -// -// The iter parameter must be an iterator on the GridFS files collection. -// Using the GridFS.Find method is an easy way to obtain such an iterator, -// but any iterator on the collection will work. -// -// If the provided *file is non-nil, OpenNext will close it before attempting -// to iterate to the next element. This means that in a loop one only -// has to worry about closing files when breaking out of the loop early -// (break, return, or panic). -// -// For example: -// -//     gfs := db.GridFS("fs") -//     query := gfs.Find(nil).Sort("filename") -//     iter := query.Iter() -//     var f *mgo.GridFile -//     for gfs.OpenNext(iter, &f) { -//         fmt.Printf("Filename: %s\n", f.Name()) -//     } -//     if iter.Close() != nil { -//         panic(iter.Close()) -//     } -// -func (gfs *GridFS) OpenNext(iter *Iter, file **GridFile) bool { -	if *file != nil { -		// Ignoring the error here shouldn't be a big deal -		// as we're reading the file and the loop iteration -		// for this file is finished. -		_ = (*file).Close() -	} -	var doc gfsFile -	if !iter.Next(&doc) { -		*file = nil -		return false -	} -	f := gfs.newFile() -	f.mode = gfsReading -	f.doc = doc -	*file = f -	return true -} - -// Find runs query on GridFS's files collection and returns -// the resulting Query. -// -// This logic: -// -//     gfs := db.GridFS("fs") -//     iter := gfs.Find(nil).Iter() -// -// Is equivalent to: -// -//     files := db.C("fs" + ".files") -//     iter := files.Find(nil).Iter() -// -func (gfs *GridFS) Find(query interface{}) *Query { -	return gfs.Files.Find(query) -} - -// RemoveId deletes the file with the provided id from the GridFS. -func (gfs *GridFS) RemoveId(id interface{}) error { -	err := gfs.Files.Remove(bson.M{"_id": id}) -	if err != nil { -		return err -	} -	_, err = gfs.Chunks.RemoveAll(bson.D{{"files_id", id}}) -	return err -} - -type gfsDocId struct { -	Id interface{} "_id" -} - -// Remove deletes all files with the provided name from the GridFS. -func (gfs *GridFS) Remove(name string) (err error) { -	iter := gfs.Files.Find(bson.M{"filename": name}).Select(bson.M{"_id": 1}).Iter() -	var doc gfsDocId -	for iter.Next(&doc) { -		if e := gfs.RemoveId(doc.Id); e != nil { -			err = e -		} -	} -	if err == nil { -		err = iter.Close() -	} -	return err -} - -func (file *GridFile) assertMode(mode gfsFileMode) { -	switch file.mode { -	case mode: -		return -	case gfsWriting: -		panic("GridFile is open for writing") -	case gfsReading: -		panic("GridFile is open for reading") -	case gfsClosed: -		panic("GridFile is closed") -	default: -		panic("internal error: missing GridFile mode") -	} -} - -// SetChunkSize sets size of saved chunks.  Once the file is written to, it -// will be split in blocks of that size and each block saved into an -// independent chunk document.  The default chunk size is 255kb. -// -// It is a runtime error to call this function once the file has started -// being written to. -func (file *GridFile) SetChunkSize(bytes int) { -	file.assertMode(gfsWriting) -	debugf("GridFile %p: setting chunk size to %d", file, bytes) -	file.m.Lock() -	file.doc.ChunkSize = bytes -	file.m.Unlock() -} - -// Id returns the current file Id. -func (file *GridFile) Id() interface{} { -	return file.doc.Id -} - -// SetId changes the current file Id. -// -// It is a runtime error to call this function once the file has started -// being written to, or when the file is not open for writing. -func (file *GridFile) SetId(id interface{}) { -	file.assertMode(gfsWriting) -	file.m.Lock() -	file.doc.Id = id -	file.m.Unlock() -} - -// Name returns the optional file name.  An empty string will be returned -// in case it is unset. -func (file *GridFile) Name() string { -	return file.doc.Filename -} - -// SetName changes the optional file name.  An empty string may be used to -// unset it. -// -// It is a runtime error to call this function when the file is not open -// for writing. -func (file *GridFile) SetName(name string) { -	file.assertMode(gfsWriting) -	file.m.Lock() -	file.doc.Filename = name -	file.m.Unlock() -} - -// ContentType returns the optional file content type.  An empty string will be -// returned in case it is unset. -func (file *GridFile) ContentType() string { -	return file.doc.ContentType -} - -// ContentType changes the optional file content type.  An empty string may be -// used to unset it. -// -// It is a runtime error to call this function when the file is not open -// for writing. -func (file *GridFile) SetContentType(ctype string) { -	file.assertMode(gfsWriting) -	file.m.Lock() -	file.doc.ContentType = ctype -	file.m.Unlock() -} - -// GetMeta unmarshals the optional "metadata" field associated with the -// file into the result parameter. The meaning of keys under that field -// is user-defined. For example: -// -//     result := struct{ INode int }{} -//     err = file.GetMeta(&result) -//     if err != nil { -//         panic(err.String()) -//     } -//     fmt.Printf("inode: %d\n", result.INode) -// -func (file *GridFile) GetMeta(result interface{}) (err error) { -	file.m.Lock() -	if file.doc.Metadata != nil { -		err = bson.Unmarshal(file.doc.Metadata.Data, result) -	} -	file.m.Unlock() -	return -} - -// SetMeta changes the optional "metadata" field associated with the -// file. The meaning of keys under that field is user-defined. -// For example: -// -//     file.SetMeta(bson.M{"inode": inode}) -// -// It is a runtime error to call this function when the file is not open -// for writing. -func (file *GridFile) SetMeta(metadata interface{}) { -	file.assertMode(gfsWriting) -	data, err := bson.Marshal(metadata) -	file.m.Lock() -	if err != nil && file.err == nil { -		file.err = err -	} else { -		file.doc.Metadata = &bson.Raw{Data: data} -	} -	file.m.Unlock() -} - -// Size returns the file size in bytes. -func (file *GridFile) Size() (bytes int64) { -	file.m.Lock() -	bytes = file.doc.Length -	file.m.Unlock() -	return -} - -// MD5 returns the file MD5 as a hex-encoded string. -func (file *GridFile) MD5() (md5 string) { -	return file.doc.MD5 -} - -// UploadDate returns the file upload time. -func (file *GridFile) UploadDate() time.Time { -	return file.doc.UploadDate -} - -// SetUploadDate changes the file upload time. -// -// It is a runtime error to call this function when the file is not open -// for writing. -func (file *GridFile) SetUploadDate(t time.Time) { -	file.assertMode(gfsWriting) -	file.m.Lock() -	file.doc.UploadDate = t -	file.m.Unlock() -} - -// Close flushes any pending changes in case the file is being written -// to, waits for any background operations to finish, and closes the file. -// -// It's important to Close files whether they are being written to -// or read from, and to check the err result to ensure the operation -// completed successfully. -func (file *GridFile) Close() (err error) { -	file.m.Lock() -	defer file.m.Unlock() -	if file.mode == gfsWriting { -		if len(file.wbuf) > 0 && file.err == nil { -			file.insertChunk(file.wbuf) -			file.wbuf = file.wbuf[0:0] -		} -		file.completeWrite() -	} else if file.mode == gfsReading && file.rcache != nil { -		file.rcache.wait.Lock() -		file.rcache = nil -	} -	file.mode = gfsClosed -	debugf("GridFile %p: closed", file) -	return file.err -} - -func (file *GridFile) completeWrite() { -	for file.wpending > 0 { -		debugf("GridFile %p: waiting for %d pending chunks to complete file write", file, file.wpending) -		file.c.Wait() -	} -	if file.err == nil { -		hexsum := hex.EncodeToString(file.wsum.Sum(nil)) -		if file.doc.UploadDate.IsZero() { -			file.doc.UploadDate = bson.Now() -		} -		file.doc.MD5 = hexsum -		file.err = file.gfs.Files.Insert(file.doc) -	} -	if file.err != nil { -		file.gfs.Chunks.RemoveAll(bson.D{{"files_id", file.doc.Id}}) -	} -	if file.err == nil { -		index := Index{ -			Key:    []string{"files_id", "n"}, -			Unique: true, -		} -		file.err = file.gfs.Chunks.EnsureIndex(index) -	} -} - -// Abort cancels an in-progress write, preventing the file from being -// automically created and ensuring previously written chunks are -// removed when the file is closed. -// -// It is a runtime error to call Abort when the file was not opened -// for writing. -func (file *GridFile) Abort() { -	if file.mode != gfsWriting { -		panic("file.Abort must be called on file opened for writing") -	} -	file.err = errors.New("write aborted") -} - -// Write writes the provided data to the file and returns the -// number of bytes written and an error in case something -// wrong happened. -// -// The file will internally cache the data so that all but the last -// chunk sent to the database have the size defined by SetChunkSize. -// This also means that errors may be deferred until a future call -// to Write or Close. -// -// The parameters and behavior of this function turn the file -// into an io.Writer. -func (file *GridFile) Write(data []byte) (n int, err error) { -	file.assertMode(gfsWriting) -	file.m.Lock() -	debugf("GridFile %p: writing %d bytes", file, len(data)) -	defer file.m.Unlock() - -	if file.err != nil { -		return 0, file.err -	} - -	n = len(data) -	file.doc.Length += int64(n) -	chunkSize := file.doc.ChunkSize - -	if len(file.wbuf)+len(data) < chunkSize { -		file.wbuf = append(file.wbuf, data...) -		return -	} - -	// First, flush file.wbuf complementing with data. -	if len(file.wbuf) > 0 { -		missing := chunkSize - len(file.wbuf) -		if missing > len(data) { -			missing = len(data) -		} -		file.wbuf = append(file.wbuf, data[:missing]...) -		data = data[missing:] -		file.insertChunk(file.wbuf) -		file.wbuf = file.wbuf[0:0] -	} - -	// Then, flush all chunks from data without copying. -	for len(data) > chunkSize { -		size := chunkSize -		if size > len(data) { -			size = len(data) -		} -		file.insertChunk(data[:size]) -		data = data[size:] -	} - -	// And append the rest for a future call. -	file.wbuf = append(file.wbuf, data...) - -	return n, file.err -} - -func (file *GridFile) insertChunk(data []byte) { -	n := file.chunk -	file.chunk++ -	debugf("GridFile %p: adding to checksum: %q", file, string(data)) -	file.wsum.Write(data) - -	for file.doc.ChunkSize*file.wpending >= 1024*1024 { -		// Hold on.. we got a MB pending. -		file.c.Wait() -		if file.err != nil { -			return -		} -	} - -	file.wpending++ - -	debugf("GridFile %p: inserting chunk %d with %d bytes", file, n, len(data)) - -	// We may not own the memory of data, so rather than -	// simply copying it, we'll marshal the document ahead of time. -	data, err := bson.Marshal(gfsChunk{bson.NewObjectId(), file.doc.Id, n, data}) -	if err != nil { -		file.err = err -		return -	} - -	go func() { -		err := file.gfs.Chunks.Insert(bson.Raw{Data: data}) -		file.m.Lock() -		file.wpending-- -		if err != nil && file.err == nil { -			file.err = err -		} -		file.c.Broadcast() -		file.m.Unlock() -	}() -} - -// Seek sets the offset for the next Read or Write on file to -// offset, interpreted according to whence: 0 means relative to -// the origin of the file, 1 means relative to the current offset, -// and 2 means relative to the end. It returns the new offset and -// an error, if any. -func (file *GridFile) Seek(offset int64, whence int) (pos int64, err error) { -	file.m.Lock() -	debugf("GridFile %p: seeking for %s (whence=%d)", file, offset, whence) -	defer file.m.Unlock() -	switch whence { -	case os.SEEK_SET: -	case os.SEEK_CUR: -		offset += file.offset -	case os.SEEK_END: -		offset += file.doc.Length -	default: -		panic("unsupported whence value") -	} -	if offset > file.doc.Length { -		return file.offset, errors.New("seek past end of file") -	} -	if offset == file.doc.Length { -		// If we're seeking to the end of the file, -		// no need to read anything. This enables -		// a client to find the size of the file using only the -		// io.ReadSeeker interface with low overhead. -		file.offset = offset -		return file.offset, nil -	} -	chunk := int(offset / int64(file.doc.ChunkSize)) -	if chunk+1 == file.chunk && offset >= file.offset { -		file.rbuf = file.rbuf[int(offset-file.offset):] -		file.offset = offset -		return file.offset, nil -	} -	file.offset = offset -	file.chunk = chunk -	file.rbuf = nil -	file.rbuf, err = file.getChunk() -	if err == nil { -		file.rbuf = file.rbuf[int(file.offset-int64(chunk)*int64(file.doc.ChunkSize)):] -	} -	return file.offset, err -} - -// Read reads into b the next available data from the file and -// returns the number of bytes written and an error in case -// something wrong happened.  At the end of the file, n will -// be zero and err will be set to io.EOF. -// -// The parameters and behavior of this function turn the file -// into an io.Reader. -func (file *GridFile) Read(b []byte) (n int, err error) { -	file.assertMode(gfsReading) -	file.m.Lock() -	debugf("GridFile %p: reading at offset %d into buffer of length %d", file, file.offset, len(b)) -	defer file.m.Unlock() -	if file.offset == file.doc.Length { -		return 0, io.EOF -	} -	for err == nil { -		i := copy(b, file.rbuf) -		n += i -		file.offset += int64(i) -		file.rbuf = file.rbuf[i:] -		if i == len(b) || file.offset == file.doc.Length { -			break -		} -		b = b[i:] -		file.rbuf, err = file.getChunk() -	} -	return n, err -} - -func (file *GridFile) getChunk() (data []byte, err error) { -	cache := file.rcache -	file.rcache = nil -	if cache != nil && cache.n == file.chunk { -		debugf("GridFile %p: Getting chunk %d from cache", file, file.chunk) -		cache.wait.Lock() -		data, err = cache.data, cache.err -	} else { -		debugf("GridFile %p: Fetching chunk %d", file, file.chunk) -		var doc gfsChunk -		err = file.gfs.Chunks.Find(bson.D{{"files_id", file.doc.Id}, {"n", file.chunk}}).One(&doc) -		data = doc.Data -	} -	file.chunk++ -	if int64(file.chunk)*int64(file.doc.ChunkSize) < file.doc.Length { -		// Read the next one in background. -		cache = &gfsCachedChunk{n: file.chunk} -		cache.wait.Lock() -		debugf("GridFile %p: Scheduling chunk %d for background caching", file, file.chunk) -		// Clone the session to avoid having it closed in between. -		chunks := file.gfs.Chunks -		session := chunks.Database.Session.Clone() -		go func(id interface{}, n int) { -			defer session.Close() -			chunks = chunks.With(session) -			var doc gfsChunk -			cache.err = chunks.Find(bson.D{{"files_id", id}, {"n", n}}).One(&doc) -			cache.data = doc.Data -			cache.wait.Unlock() -		}(file.doc.Id, file.chunk) -		file.rcache = cache -	} -	debugf("Returning err: %#v", err) -	return -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/LICENSE b/vendor/gopkg.in/mgo.v2/internal/json/LICENSE deleted file mode 100644 index 7448756..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -   * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -   * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. -   * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gopkg.in/mgo.v2/internal/json/decode.go b/vendor/gopkg.in/mgo.v2/internal/json/decode.go deleted file mode 100644 index ce7c7d2..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/decode.go +++ /dev/null @@ -1,1685 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package json - -import ( -	"bytes" -	"encoding" -	"encoding/base64" -	"errors" -	"fmt" -	"reflect" -	"runtime" -	"strconv" -	"unicode" -	"unicode/utf16" -	"unicode/utf8" -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. -// -// Unmarshal uses the inverse of the encodings that -// Marshal uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. -// Unmarshal will only set exported fields of the struct. -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -//	bool, for JSON booleans -//	float64, for JSON numbers -//	string, for JSON strings -//	[]interface{}, for JSON arrays -//	map[string]interface{}, for JSON objects -//	nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores key- -// value pairs from the JSON object into the map.  The map's key type must -// either be a string or implement encoding.TextUnmarshaler. -// -// If a JSON value is not appropriate for a given target type, -// or if a JSON number overflows the target type, Unmarshal -// skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an UnmarshalTypeError describing the earliest such error. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// ``not present,'' unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -// -func Unmarshal(data []byte, v interface{}) error { -	// Check for well-formedness. -	// Avoids filling out half a data structure -	// before discovering a JSON syntax error. -	var d decodeState -	err := checkValid(data, &d.scan) -	if err != nil { -		return err -	} - -	d.init(data) -	return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -type Unmarshaler interface { -	UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -type UnmarshalTypeError struct { -	Value  string       // description of JSON value - "bool", "array", "number -5" -	Type   reflect.Type // type of Go value it could not be assigned to -	Offset int64        // error occurred after reading Offset bytes -} - -func (e *UnmarshalTypeError) Error() string { -	return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// (No longer used; kept for compatibility.) -type UnmarshalFieldError struct { -	Key   string -	Type  reflect.Type -	Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { -	return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. -// (The argument to Unmarshal must be a non-nil pointer.) -type InvalidUnmarshalError struct { -	Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { -	if e.Type == nil { -		return "json: Unmarshal(nil)" -	} - -	if e.Type.Kind() != reflect.Ptr { -		return "json: Unmarshal(non-pointer " + e.Type.String() + ")" -	} -	return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v interface{}) (err error) { -	defer func() { -		if r := recover(); r != nil { -			if _, ok := r.(runtime.Error); ok { -				panic(r) -			} -			err = r.(error) -		} -	}() - -	rv := reflect.ValueOf(v) -	if rv.Kind() != reflect.Ptr || rv.IsNil() { -		return &InvalidUnmarshalError{reflect.TypeOf(v)} -	} - -	d.scan.reset() -	// We decode rv not rv.Elem because the Unmarshaler interface -	// test must be applied at the top level of the value. -	d.value(rv) -	return d.savedError -} - -// A Number represents a JSON number literal. -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { -	return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { -	return strconv.ParseInt(string(n), 10, 64) -} - -// isValidNumber reports whether s is a valid JSON number literal. -func isValidNumber(s string) bool { -	// This function implements the JSON numbers grammar. -	// See https://tools.ietf.org/html/rfc7159#section-6 -	// and http://json.org/number.gif - -	if s == "" { -		return false -	} - -	// Optional - -	if s[0] == '-' { -		s = s[1:] -		if s == "" { -			return false -		} -	} - -	// Digits -	switch { -	default: -		return false - -	case s[0] == '0': -		s = s[1:] - -	case '1' <= s[0] && s[0] <= '9': -		s = s[1:] -		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { -			s = s[1:] -		} -	} - -	// . followed by 1 or more digits. -	if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { -		s = s[2:] -		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { -			s = s[1:] -		} -	} - -	// e or E followed by an optional - or + and -	// 1 or more digits. -	if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { -		s = s[1:] -		if s[0] == '+' || s[0] == '-' { -			s = s[1:] -			if s == "" { -				return false -			} -		} -		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { -			s = s[1:] -		} -	} - -	// Make sure we are at the end. -	return s == "" -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { -	data       []byte -	off        int // read offset in data -	scan       scanner -	nextscan   scanner // for calls to nextValue -	savedError error -	useNumber  bool -	ext        Extension -} - -// errPhase is used for errors that should not happen unless -// there is a bug in the JSON decoder or something is editing -// the data slice while the decoder executes. -var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?") - -func (d *decodeState) init(data []byte) *decodeState { -	d.data = data -	d.off = 0 -	d.savedError = nil -	return d -} - -// error aborts the decoding by panicking with err. -func (d *decodeState) error(err error) { -	panic(err) -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { -	if d.savedError == nil { -		d.savedError = err -	} -} - -// next cuts off and returns the next full JSON value in d.data[d.off:]. -// The next value is known to be an object or array, not a literal. -func (d *decodeState) next() []byte { -	c := d.data[d.off] -	item, rest, err := nextValue(d.data[d.off:], &d.nextscan) -	if err != nil { -		d.error(err) -	} -	d.off = len(d.data) - len(rest) - -	// Our scanner has seen the opening brace/bracket -	// and thinks we're still in the middle of the object. -	// invent a closing brace/bracket to get it out. -	if c == '{' { -		d.scan.step(&d.scan, '}') -	} else if c == '[' { -		d.scan.step(&d.scan, ']') -	} else { -		// Was inside a function name. Get out of it. -		d.scan.step(&d.scan, '(') -		d.scan.step(&d.scan, ')') -	} - -	return item -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -// It updates d.off and returns the new scan code. -func (d *decodeState) scanWhile(op int) int { -	var newOp int -	for { -		if d.off >= len(d.data) { -			newOp = d.scan.eof() -			d.off = len(d.data) + 1 // mark processed EOF with len+1 -		} else { -			c := d.data[d.off] -			d.off++ -			newOp = d.scan.step(&d.scan, c) -		} -		if newOp != op { -			break -		} -	} -	return newOp -} - -// value decodes a JSON value from d.data[d.off:] into the value. -// it updates d.off to point past the decoded value. -func (d *decodeState) value(v reflect.Value) { -	if !v.IsValid() { -		_, rest, err := nextValue(d.data[d.off:], &d.nextscan) -		if err != nil { -			d.error(err) -		} -		d.off = len(d.data) - len(rest) - -		// d.scan thinks we're still at the beginning of the item. -		// Feed in an empty string - the shortest, simplest value - -		// so that it knows we got to the end of the value. -		if d.scan.redo { -			// rewind. -			d.scan.redo = false -			d.scan.step = stateBeginValue -		} -		d.scan.step(&d.scan, '"') -		d.scan.step(&d.scan, '"') - -		n := len(d.scan.parseState) -		if n > 0 && d.scan.parseState[n-1] == parseObjectKey { -			// d.scan thinks we just read an object key; finish the object -			d.scan.step(&d.scan, ':') -			d.scan.step(&d.scan, '"') -			d.scan.step(&d.scan, '"') -			d.scan.step(&d.scan, '}') -		} - -		return -	} - -	switch op := d.scanWhile(scanSkipSpace); op { -	default: -		d.error(errPhase) - -	case scanBeginArray: -		d.array(v) - -	case scanBeginObject: -		d.object(v) - -	case scanBeginLiteral: -		d.literal(v) - -	case scanBeginName: -		d.name(v) -	} -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() interface{} { -	switch op := d.scanWhile(scanSkipSpace); op { -	default: -		d.error(errPhase) - -	case scanBeginArray: -		d.array(reflect.Value{}) - -	case scanBeginObject: -		d.object(reflect.Value{}) - -	case scanBeginName: -		switch v := d.nameInterface().(type) { -		case nil, string: -			return v -		} - -	case scanBeginLiteral: -		switch v := d.literalInterface().(type) { -		case nil, string: -			return v -		} -	} -	return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// if it encounters an Unmarshaler, indirect stops and returns that. -// if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { -	// If v is a named type and is addressable, -	// start with its address, so that if the type has pointer methods, -	// we find them. -	if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { -		v = v.Addr() -	} -	for { -		// Load value from interface, but only if the result will be -		// usefully addressable. -		if v.Kind() == reflect.Interface && !v.IsNil() { -			e := v.Elem() -			if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { -				v = e -				continue -			} -		} - -		if v.Kind() != reflect.Ptr { -			break -		} - -		if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() { -			break -		} -		if v.IsNil() { -			v.Set(reflect.New(v.Type().Elem())) -		} -		if v.Type().NumMethod() > 0 { -			if u, ok := v.Interface().(Unmarshaler); ok { -				return u, nil, v -			} -			if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { -				return nil, u, v -			} -		} -		v = v.Elem() -	} -	return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into the value v. -// the first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) { -	// Check for unmarshaler. -	u, ut, pv := d.indirect(v, false) -	if u != nil { -		d.off-- -		err := u.UnmarshalJSON(d.next()) -		if err != nil { -			d.error(err) -		} -		return -	} -	if ut != nil { -		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) -		d.off-- -		d.next() -		return -	} - -	v = pv - -	// Check type of target. -	switch v.Kind() { -	case reflect.Interface: -		if v.NumMethod() == 0 { -			// Decoding into nil interface?  Switch to non-reflect code. -			v.Set(reflect.ValueOf(d.arrayInterface())) -			return -		} -		// Otherwise it's invalid. -		fallthrough -	default: -		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) -		d.off-- -		d.next() -		return -	case reflect.Array: -	case reflect.Slice: -		break -	} - -	i := 0 -	for { -		// Look ahead for ] - can only happen on first iteration. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndArray { -			break -		} - -		// Back up so d.value can have the byte we just read. -		d.off-- -		d.scan.undo(op) - -		// Get element of array, growing if necessary. -		if v.Kind() == reflect.Slice { -			// Grow slice if necessary -			if i >= v.Cap() { -				newcap := v.Cap() + v.Cap()/2 -				if newcap < 4 { -					newcap = 4 -				} -				newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) -				reflect.Copy(newv, v) -				v.Set(newv) -			} -			if i >= v.Len() { -				v.SetLen(i + 1) -			} -		} - -		if i < v.Len() { -			// Decode into element. -			d.value(v.Index(i)) -		} else { -			// Ran out of fixed array: skip. -			d.value(reflect.Value{}) -		} -		i++ - -		// Next token must be , or ]. -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndArray { -			break -		} -		if op != scanArrayValue { -			d.error(errPhase) -		} -	} - -	if i < v.Len() { -		if v.Kind() == reflect.Array { -			// Array. Zero the rest. -			z := reflect.Zero(v.Type().Elem()) -			for ; i < v.Len(); i++ { -				v.Index(i).Set(z) -			} -		} else { -			v.SetLen(i) -		} -	} -	if i == 0 && v.Kind() == reflect.Slice { -		v.Set(reflect.MakeSlice(v.Type(), 0, 0)) -	} -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() - -// object consumes an object from d.data[d.off-1:], decoding into the value v. -// the first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) { -	// Check for unmarshaler. -	u, ut, pv := d.indirect(v, false) -	if d.storeKeyed(pv) { -		return -	} -	if u != nil { -		d.off-- -		err := u.UnmarshalJSON(d.next()) -		if err != nil { -			d.error(err) -		} -		return -	} -	if ut != nil { -		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -		d.off-- -		d.next() // skip over { } in input -		return -	} -	v = pv - -	// Decoding into nil interface?  Switch to non-reflect code. -	if v.Kind() == reflect.Interface && v.NumMethod() == 0 { -		v.Set(reflect.ValueOf(d.objectInterface())) -		return -	} - -	// Check type of target: -	//   struct or -	//   map[string]T or map[encoding.TextUnmarshaler]T -	switch v.Kind() { -	case reflect.Map: -		// Map key must either have string kind or be an encoding.TextUnmarshaler. -		t := v.Type() -		if t.Key().Kind() != reflect.String && -			!reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { -			d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -			d.off-- -			d.next() // skip over { } in input -			return -		} -		if v.IsNil() { -			v.Set(reflect.MakeMap(t)) -		} -	case reflect.Struct: - -	default: -		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -		d.off-- -		d.next() // skip over { } in input -		return -	} - -	var mapElem reflect.Value - -	empty := true -	for { -		// Read opening " of string key or closing }. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndObject { -			if !empty && !d.ext.trailingCommas { -				d.syntaxError("beginning of object key string") -			} -			break -		} -		empty = false -		if op == scanBeginName { -			if !d.ext.unquotedKeys { -				d.syntaxError("beginning of object key string") -			} -		} else if op != scanBeginLiteral { -			d.error(errPhase) -		} -		unquotedKey := op == scanBeginName - -		// Read key. -		start := d.off - 1 -		op = d.scanWhile(scanContinue) -		item := d.data[start : d.off-1] -		var key []byte -		if unquotedKey { -			key = item -			// TODO Fix code below to quote item when necessary. -		} else { -			var ok bool -			key, ok = unquoteBytes(item) -			if !ok { -				d.error(errPhase) -			} -		} - -		// Figure out field corresponding to key. -		var subv reflect.Value -		destring := false // whether the value is wrapped in a string to be decoded first - -		if v.Kind() == reflect.Map { -			elemType := v.Type().Elem() -			if !mapElem.IsValid() { -				mapElem = reflect.New(elemType).Elem() -			} else { -				mapElem.Set(reflect.Zero(elemType)) -			} -			subv = mapElem -		} else { -			var f *field -			fields := cachedTypeFields(v.Type()) -			for i := range fields { -				ff := &fields[i] -				if bytes.Equal(ff.nameBytes, key) { -					f = ff -					break -				} -				if f == nil && ff.equalFold(ff.nameBytes, key) { -					f = ff -				} -			} -			if f != nil { -				subv = v -				destring = f.quoted -				for _, i := range f.index { -					if subv.Kind() == reflect.Ptr { -						if subv.IsNil() { -							subv.Set(reflect.New(subv.Type().Elem())) -						} -						subv = subv.Elem() -					} -					subv = subv.Field(i) -				} -			} -		} - -		// Read : before value. -		if op == scanSkipSpace { -			op = d.scanWhile(scanSkipSpace) -		} -		if op != scanObjectKey { -			d.error(errPhase) -		} - -		// Read value. -		if destring { -			switch qv := d.valueQuoted().(type) { -			case nil: -				d.literalStore(nullLiteral, subv, false) -			case string: -				d.literalStore([]byte(qv), subv, true) -			default: -				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) -			} -		} else { -			d.value(subv) -		} - -		// Write value back to map; -		// if using struct, subv points into struct already. -		if v.Kind() == reflect.Map { -			kt := v.Type().Key() -			var kv reflect.Value -			switch { -			case kt.Kind() == reflect.String: -				kv = reflect.ValueOf(key).Convert(v.Type().Key()) -			case reflect.PtrTo(kt).Implements(textUnmarshalerType): -				kv = reflect.New(v.Type().Key()) -				d.literalStore(item, kv, true) -				kv = kv.Elem() -			default: -				panic("json: Unexpected key type") // should never occur -			} -			v.SetMapIndex(kv, subv) -		} - -		// Next token must be , or }. -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndObject { -			break -		} -		if op != scanObjectValue { -			d.error(errPhase) -		} -	} -} - -// isNull returns whether there's a null literal at the provided offset. -func (d *decodeState) isNull(off int) bool { -	if off+4 >= len(d.data) || d.data[off] != 'n' || d.data[off+1] != 'u' || d.data[off+2] != 'l' || d.data[off+3] != 'l' { -		return false -	} -	d.nextscan.reset() -	for i, c := range d.data[off:] { -		if i > 4 { -			return false -		} -		switch d.nextscan.step(&d.nextscan, c) { -		case scanContinue, scanBeginName: -			continue -		} -		break -	} -	return true -} - -// name consumes a const or function from d.data[d.off-1:], decoding into the value v. -// the first byte of the function name has been read already. -func (d *decodeState) name(v reflect.Value) { -	if d.isNull(d.off-1) { -		d.literal(v) -		return -	} - -	// Check for unmarshaler. -	u, ut, pv := d.indirect(v, false) -	if d.storeKeyed(pv) { -		return -	} -	if u != nil { -		d.off-- -		err := u.UnmarshalJSON(d.next()) -		if err != nil { -			d.error(err) -		} -		return -	} -	if ut != nil { -		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -		d.off-- -		d.next() // skip over function in input -		return -	} -	v = pv - -	// Decoding into nil interface?  Switch to non-reflect code. -	if v.Kind() == reflect.Interface && v.NumMethod() == 0 { -		out := d.nameInterface() -		if out == nil { -			v.Set(reflect.Zero(v.Type())) -		} else { -			v.Set(reflect.ValueOf(out)) -		} -		return -	} - -	nameStart := d.off - 1 - -	op := d.scanWhile(scanContinue) - -	name := d.data[nameStart : d.off-1] -	if op != scanParam { -		// Back up so the byte just read is consumed next. -		d.off-- -		d.scan.undo(op) -		if l, ok := d.convertLiteral(name); ok { -			d.storeValue(v, l) -			return -		} -		d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) -	} - -	funcName := string(name) -	funcData := d.ext.funcs[funcName] -	if funcData.key == "" { -		d.error(fmt.Errorf("json: unknown function %q", funcName)) -	} - -	// Check type of target: -	//   struct or -	//   map[string]T or map[encoding.TextUnmarshaler]T -	switch v.Kind() { -	case reflect.Map: -		// Map key must either have string kind or be an encoding.TextUnmarshaler. -		t := v.Type() -		if t.Key().Kind() != reflect.String && -			!reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { -			d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -			d.off-- -			d.next() // skip over { } in input -			return -		} -		if v.IsNil() { -			v.Set(reflect.MakeMap(t)) -		} -	case reflect.Struct: - -	default: -		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -		d.off-- -		d.next() // skip over { } in input -		return -	} - -	// TODO Fix case of func field as map. -	//topv := v - -	// Figure out field corresponding to function. -	key := []byte(funcData.key) -	if v.Kind() == reflect.Map { -		elemType := v.Type().Elem() -		v = reflect.New(elemType).Elem() -	} else { -		var f *field -		fields := cachedTypeFields(v.Type()) -		for i := range fields { -			ff := &fields[i] -			if bytes.Equal(ff.nameBytes, key) { -				f = ff -				break -			} -			if f == nil && ff.equalFold(ff.nameBytes, key) { -				f = ff -			} -		} -		if f != nil { -			for _, i := range f.index { -				if v.Kind() == reflect.Ptr { -					if v.IsNil() { -						v.Set(reflect.New(v.Type().Elem())) -					} -					v = v.Elem() -				} -				v = v.Field(i) -			} -			if v.Kind() == reflect.Ptr { -				if v.IsNil() { -					v.Set(reflect.New(v.Type().Elem())) -				} -				v = v.Elem() -			} -		} -	} - -	// Check for unmarshaler on func field itself. -	u, ut, pv = d.indirect(v, false) -	if u != nil { -		d.off = nameStart -		err := u.UnmarshalJSON(d.next()) -		if err != nil { -			d.error(err) -		} -		return -	} - -	var mapElem reflect.Value - -	// Parse function arguments. -	for i := 0; ; i++ { -		// closing ) - can only happen on first iteration. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndParams { -			break -		} - -		// Back up so d.value can have the byte we just read. -		d.off-- -		d.scan.undo(op) - -		if i >= len(funcData.args) { -			d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) -		} -		key := []byte(funcData.args[i]) - -		// Figure out field corresponding to key. -		var subv reflect.Value -		destring := false // whether the value is wrapped in a string to be decoded first - -		if v.Kind() == reflect.Map { -			elemType := v.Type().Elem() -			if !mapElem.IsValid() { -				mapElem = reflect.New(elemType).Elem() -			} else { -				mapElem.Set(reflect.Zero(elemType)) -			} -			subv = mapElem -		} else { -			var f *field -			fields := cachedTypeFields(v.Type()) -			for i := range fields { -				ff := &fields[i] -				if bytes.Equal(ff.nameBytes, key) { -					f = ff -					break -				} -				if f == nil && ff.equalFold(ff.nameBytes, key) { -					f = ff -				} -			} -			if f != nil { -				subv = v -				destring = f.quoted -				for _, i := range f.index { -					if subv.Kind() == reflect.Ptr { -						if subv.IsNil() { -							subv.Set(reflect.New(subv.Type().Elem())) -						} -						subv = subv.Elem() -					} -					subv = subv.Field(i) -				} -			} -		} - -		// Read value. -		if destring { -			switch qv := d.valueQuoted().(type) { -			case nil: -				d.literalStore(nullLiteral, subv, false) -			case string: -				d.literalStore([]byte(qv), subv, true) -			default: -				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) -			} -		} else { -			d.value(subv) -		} - -		// Write value back to map; -		// if using struct, subv points into struct already. -		if v.Kind() == reflect.Map { -			kt := v.Type().Key() -			var kv reflect.Value -			switch { -			case kt.Kind() == reflect.String: -				kv = reflect.ValueOf(key).Convert(v.Type().Key()) -			case reflect.PtrTo(kt).Implements(textUnmarshalerType): -				kv = reflect.New(v.Type().Key()) -				d.literalStore(key, kv, true) -				kv = kv.Elem() -			default: -				panic("json: Unexpected key type") // should never occur -			} -			v.SetMapIndex(kv, subv) -		} - -		// Next token must be , or ). -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndParams { -			break -		} -		if op != scanParam { -			d.error(errPhase) -		} -	} -} - -// keyed attempts to decode an object or function using a keyed doc extension, -// and returns the value and true on success, or nil and false otherwise. -func (d *decodeState) keyed() (interface{}, bool) { -	if len(d.ext.keyed) == 0 { -		return nil, false -	} - -	unquote := false - -	// Look-ahead first key to check for a keyed document extension. -	d.nextscan.reset() -	var start, end int -	for i, c := range d.data[d.off-1:] { -		switch op := d.nextscan.step(&d.nextscan, c); op { -		case scanSkipSpace, scanContinue, scanBeginObject: -			continue -		case scanBeginLiteral, scanBeginName: -			unquote = op == scanBeginLiteral -			start = i -			continue -		} -		end = i -		break -	} - -	name := d.data[d.off-1+start : d.off-1+end] - -	var key []byte -	var ok bool -	if unquote { -		key, ok = unquoteBytes(name) -		if !ok { -			d.error(errPhase) -		} -	} else { -		funcData, ok := d.ext.funcs[string(name)] -		if !ok { -			return nil, false -		} -		key = []byte(funcData.key) -	} - -	decode, ok := d.ext.keyed[string(key)] -	if !ok { -		return nil, false -	} - -	d.off-- -	out, err := decode(d.next()) -	if err != nil { -		d.error(err) -	} -	return out, true -} - -func (d *decodeState) storeKeyed(v reflect.Value) bool { -	keyed, ok := d.keyed() -	if !ok { -		return false -	} -	d.storeValue(v, keyed) -	return true -} - -var ( -	trueBytes = []byte("true") -	falseBytes = []byte("false") -	nullBytes = []byte("null") -) - -func (d *decodeState) storeValue(v reflect.Value, from interface{}) { -	switch from { -	case nil: -		d.literalStore(nullBytes, v, false) -		return -	case true: -		d.literalStore(trueBytes, v, false) -		return -	case false: -		d.literalStore(falseBytes, v, false) -		return -	} -	fromv := reflect.ValueOf(from) -	for fromv.Kind() == reflect.Ptr && !fromv.IsNil() { -		fromv = fromv.Elem() -	} -	fromt := fromv.Type() -	for v.Kind() == reflect.Ptr && !v.IsNil() { -		v = v.Elem() -	} -	vt := v.Type() -	if fromt.AssignableTo(vt) { -		v.Set(fromv) -	} else if fromt.ConvertibleTo(vt) { -		v.Set(fromv.Convert(vt)) -	} else { -		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) -	} -} - -func (d *decodeState) convertLiteral(name []byte) (interface{}, bool) { -	if len(name) == 0 { -		return nil, false -	} -	switch name[0] { -	case 't': -		if bytes.Equal(name, trueBytes) { -			return true, true -		} -	case 'f': -		if bytes.Equal(name, falseBytes) { -			return false, true -		} -	case 'n': -		if bytes.Equal(name, nullBytes) { -			return nil, true -		} -	} -	if l, ok := d.ext.consts[string(name)]; ok { -		return l, true -	} -	return nil, false -} - -// literal consumes a literal from d.data[d.off-1:], decoding into the value v. -// The first byte of the literal has been read already -// (that's how the caller knows it's a literal). -func (d *decodeState) literal(v reflect.Value) { -	// All bytes inside literal return scanContinue op code. -	start := d.off - 1 -	op := d.scanWhile(scanContinue) - -	// Scan read one byte too far; back up. -	d.off-- -	d.scan.undo(op) - -	d.literalStore(d.data[start:d.off], v, false) -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (interface{}, error) { -	if d.useNumber { -		return Number(s), nil -	} -	f, err := strconv.ParseFloat(s, 64) -	if err != nil { -		return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} -	} -	return f, nil -} - -var numberType = reflect.TypeOf(Number("")) - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) { -	// Check for unmarshaler. -	if len(item) == 0 { -		//Empty string given -		d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -		return -	} -	wantptr := item[0] == 'n' // null -	u, ut, pv := d.indirect(v, wantptr) -	if u != nil { -		err := u.UnmarshalJSON(item) -		if err != nil { -			d.error(err) -		} -		return -	} -	if ut != nil { -		if item[0] != '"' { -			if fromQuoted { -				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) -			} -			return -		} -		s, ok := unquoteBytes(item) -		if !ok { -			if fromQuoted { -				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.error(errPhase) -			} -		} -		err := ut.UnmarshalText(s) -		if err != nil { -			d.error(err) -		} -		return -	} - -	v = pv - -	switch c := item[0]; c { -	case 'n': // null -		switch v.Kind() { -		case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: -			v.Set(reflect.Zero(v.Type())) -			// otherwise, ignore null for primitives/string -		} -	case 't', 'f': // true, false -		value := c == 't' -		switch v.Kind() { -		default: -			if fromQuoted { -				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) -			} -		case reflect.Bool: -			v.SetBool(value) -		case reflect.Interface: -			if v.NumMethod() == 0 { -				v.Set(reflect.ValueOf(value)) -			} else { -				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) -			} -		} - -	case '"': // string -		s, ok := unquoteBytes(item) -		if !ok { -			if fromQuoted { -				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.error(errPhase) -			} -		} -		switch v.Kind() { -		default: -			d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) -		case reflect.Slice: -			if v.Type().Elem().Kind() != reflect.Uint8 { -				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) -				break -			} -			b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) -			n, err := base64.StdEncoding.Decode(b, s) -			if err != nil { -				d.saveError(err) -				break -			} -			v.SetBytes(b[:n]) -		case reflect.String: -			v.SetString(string(s)) -		case reflect.Interface: -			if v.NumMethod() == 0 { -				v.Set(reflect.ValueOf(string(s))) -			} else { -				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) -			} -		} - -	default: // number -		if c != '-' && (c < '0' || c > '9') { -			if fromQuoted { -				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.error(errPhase) -			} -		} -		s := string(item) -		switch v.Kind() { -		default: -			if v.Kind() == reflect.String && v.Type() == numberType { -				v.SetString(s) -				if !isValidNumber(s) { -					d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) -				} -				break -			} -			if fromQuoted { -				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) -			} else { -				d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) -			} -		case reflect.Interface: -			n, err := d.convertNumber(s) -			if err != nil { -				d.saveError(err) -				break -			} -			if v.NumMethod() != 0 { -				d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) -				break -			} -			v.Set(reflect.ValueOf(n)) - -		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -			n, err := strconv.ParseInt(s, 10, 64) -			if err != nil || v.OverflowInt(n) { -				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) -				break -			} -			v.SetInt(n) - -		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -			n, err := strconv.ParseUint(s, 10, 64) -			if err != nil || v.OverflowUint(n) { -				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) -				break -			} -			v.SetUint(n) - -		case reflect.Float32, reflect.Float64: -			n, err := strconv.ParseFloat(s, v.Type().Bits()) -			if err != nil || v.OverflowFloat(n) { -				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) -				break -			} -			v.SetFloat(n) -		} -	} -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() interface{} { -	switch d.scanWhile(scanSkipSpace) { -	default: -		d.error(errPhase) -		panic("unreachable") -	case scanBeginArray: -		return d.arrayInterface() -	case scanBeginObject: -		return d.objectInterface() -	case scanBeginLiteral: -		return d.literalInterface() -	case scanBeginName: -		return d.nameInterface() -	} -} - -func (d *decodeState) syntaxError(expected string) { -	msg := fmt.Sprintf("invalid character '%c' looking for %s", d.data[d.off-1], expected) -	d.error(&SyntaxError{msg, int64(d.off)}) -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []interface{} { -	var v = make([]interface{}, 0) -	for { -		// Look ahead for ] - can only happen on first iteration. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndArray { -			if len(v) > 0 && !d.ext.trailingCommas { -				d.syntaxError("beginning of value") -			} -			break -		} - -		// Back up so d.value can have the byte we just read. -		d.off-- -		d.scan.undo(op) - -		v = append(v, d.valueInterface()) - -		// Next token must be , or ]. -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndArray { -			break -		} -		if op != scanArrayValue { -			d.error(errPhase) -		} -	} -	return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() interface{} { -	v, ok := d.keyed() -	if ok { -		return v -	} - -	m := make(map[string]interface{}) -	for { -		// Read opening " of string key or closing }. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndObject { -			if len(m) > 0 && !d.ext.trailingCommas { -				d.syntaxError("beginning of object key string") -			} -			break -		} -		if op == scanBeginName { -			if !d.ext.unquotedKeys { -				d.syntaxError("beginning of object key string") -			} -		} else if op != scanBeginLiteral { -			d.error(errPhase) -		} -		unquotedKey := op == scanBeginName - -		// Read string key. -		start := d.off - 1 -		op = d.scanWhile(scanContinue) -		item := d.data[start : d.off-1] -		var key string -		if unquotedKey { -			key = string(item) -		} else { -			var ok bool -			key, ok = unquote(item) -			if !ok { -				d.error(errPhase) -			} -		} - -		// Read : before value. -		if op == scanSkipSpace { -			op = d.scanWhile(scanSkipSpace) -		} -		if op != scanObjectKey { -			d.error(errPhase) -		} - -		// Read value. -		m[key] = d.valueInterface() - -		// Next token must be , or }. -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndObject { -			break -		} -		if op != scanObjectValue { -			d.error(errPhase) -		} -	} -	return m -} - -// literalInterface is like literal but returns an interface value. -func (d *decodeState) literalInterface() interface{} { -	// All bytes inside literal return scanContinue op code. -	start := d.off - 1 -	op := d.scanWhile(scanContinue) - -	// Scan read one byte too far; back up. -	d.off-- -	d.scan.undo(op) -	item := d.data[start:d.off] - -	switch c := item[0]; c { -	case 'n': // null -		return nil - -	case 't', 'f': // true, false -		return c == 't' - -	case '"': // string -		s, ok := unquote(item) -		if !ok { -			d.error(errPhase) -		} -		return s - -	default: // number -		if c != '-' && (c < '0' || c > '9') { -			d.error(errPhase) -		} -		n, err := d.convertNumber(string(item)) -		if err != nil { -			d.saveError(err) -		} -		return n -	} -} - -// nameInterface is like function but returns map[string]interface{}. -func (d *decodeState) nameInterface() interface{} { -	v, ok := d.keyed() -	if ok { -		return v -	} - -	nameStart := d.off - 1 - -	op := d.scanWhile(scanContinue) - -	name := d.data[nameStart : d.off-1] -	if op != scanParam { -		// Back up so the byte just read is consumed next. -		d.off-- -		d.scan.undo(op) -		if l, ok := d.convertLiteral(name); ok { -			return l -		} -		d.error(&SyntaxError{fmt.Sprintf("json: unknown constant %q", name), int64(d.off)}) -	} - -	funcName := string(name) -	funcData := d.ext.funcs[funcName] -	if funcData.key == "" { -		d.error(fmt.Errorf("json: unknown function %q", funcName)) -	} - -	m := make(map[string]interface{}) -	for i := 0; ; i++ { -		// Look ahead for ) - can only happen on first iteration. -		op := d.scanWhile(scanSkipSpace) -		if op == scanEndParams { -			break -		} - -		// Back up so d.value can have the byte we just read. -		d.off-- -		d.scan.undo(op) - -		if i >= len(funcData.args) { -			d.error(fmt.Errorf("json: too many arguments for function %s", funcName)) -		} -		m[funcData.args[i]] = d.valueInterface() - -		// Next token must be , or ). -		op = d.scanWhile(scanSkipSpace) -		if op == scanEndParams { -			break -		} -		if op != scanParam { -			d.error(errPhase) -		} -	} -	return map[string]interface{}{funcData.key: m} -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { -	if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { -		return -1 -	} -	r, err := strconv.ParseUint(string(s[2:6]), 16, 64) -	if err != nil { -		return -1 -	} -	return rune(r) -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { -	s, ok = unquoteBytes(s) -	t = string(s) -	return -} - -func unquoteBytes(s []byte) (t []byte, ok bool) { -	if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { -		return -	} -	s = s[1 : len(s)-1] - -	// Check for unusual characters. If there are none, -	// then no unquoting is needed, so return a slice of the -	// original bytes. -	r := 0 -	for r < len(s) { -		c := s[r] -		if c == '\\' || c == '"' || c < ' ' { -			break -		} -		if c < utf8.RuneSelf { -			r++ -			continue -		} -		rr, size := utf8.DecodeRune(s[r:]) -		if rr == utf8.RuneError && size == 1 { -			break -		} -		r += size -	} -	if r == len(s) { -		return s, true -	} - -	b := make([]byte, len(s)+2*utf8.UTFMax) -	w := copy(b, s[0:r]) -	for r < len(s) { -		// Out of room?  Can only happen if s is full of -		// malformed UTF-8 and we're replacing each -		// byte with RuneError. -		if w >= len(b)-2*utf8.UTFMax { -			nb := make([]byte, (len(b)+utf8.UTFMax)*2) -			copy(nb, b[0:w]) -			b = nb -		} -		switch c := s[r]; { -		case c == '\\': -			r++ -			if r >= len(s) { -				return -			} -			switch s[r] { -			default: -				return -			case '"', '\\', '/', '\'': -				b[w] = s[r] -				r++ -				w++ -			case 'b': -				b[w] = '\b' -				r++ -				w++ -			case 'f': -				b[w] = '\f' -				r++ -				w++ -			case 'n': -				b[w] = '\n' -				r++ -				w++ -			case 'r': -				b[w] = '\r' -				r++ -				w++ -			case 't': -				b[w] = '\t' -				r++ -				w++ -			case 'u': -				r-- -				rr := getu4(s[r:]) -				if rr < 0 { -					return -				} -				r += 6 -				if utf16.IsSurrogate(rr) { -					rr1 := getu4(s[r:]) -					if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { -						// A valid pair; consume. -						r += 6 -						w += utf8.EncodeRune(b[w:], dec) -						break -					} -					// Invalid surrogate; fall back to replacement rune. -					rr = unicode.ReplacementChar -				} -				w += utf8.EncodeRune(b[w:], rr) -			} - -		// Quote, control characters are invalid. -		case c == '"', c < ' ': -			return - -		// ASCII -		case c < utf8.RuneSelf: -			b[w] = c -			r++ -			w++ - -		// Coerce to well-formed UTF-8. -		default: -			rr, size := utf8.DecodeRune(s[r:]) -			r += size -			w += utf8.EncodeRune(b[w:], rr) -		} -	} -	return b[0:w], true -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/encode.go b/vendor/gopkg.in/mgo.v2/internal/json/encode.go deleted file mode 100644 index 67a0f00..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/encode.go +++ /dev/null @@ -1,1256 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 4627. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package json - -import ( -	"bytes" -	"encoding" -	"encoding/base64" -	"fmt" -	"math" -	"reflect" -	"runtime" -	"sort" -	"strconv" -	"strings" -	"sync" -	"unicode" -	"unicode/utf8" -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements the Marshaler interface -// and is not a nil pointer, Marshal calls its MarshalJSON method -// to produce JSON. If no MarshalJSON method is present but the -// value implements encoding.TextMarshaler instead, Marshal calls -// its MarshalText method. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// UnmarshalJSON. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and Number values encode as JSON numbers. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" -// to keep some browsers from misinterpreting JSON output as HTML. -// Ampersand "&" is also escaped to "\u0026" for the same reason. -// This escaping can be disabled using an Encoder with DisableHTMLEscaping. -// -// Array and slice values encode as JSON arrays, except that -// []byte encodes as a base64-encoded string, and a nil slice -// encodes as the null JSON value. -// -// Struct values encode as JSON objects. Each exported struct field -// becomes a member of the object unless -//   - the field's tag is "-", or -//   - the field is empty and its tag specifies the "omitempty" option. -// The empty values are false, 0, any -// nil pointer or interface value, and any array, slice, map, or string of -// length zero. The object's default key string is the struct field name -// but can be specified in the struct field's tag value. The "json" key in -// the struct field's tag value is the key name, followed by an optional comma -// and options. Examples: -// -//   // Field is ignored by this package. -//   Field int `json:"-"` -// -//   // Field appears in JSON as key "myName". -//   Field int `json:"myName"` -// -//   // Field appears in JSON as key "myName" and -//   // the field is omitted from the object if its value is empty, -//   // as defined above. -//   Field int `json:"myName,omitempty"` -// -//   // Field appears in JSON as key "Field" (the default), but -//   // the field is skipped if empty. -//   // Note the leading comma. -//   Field int `json:",omitempty"` -// -// The "string" option signals that a field is stored as JSON inside a -// JSON-encoded string. It applies only to fields of string, floating point, -// integer, or boolean types. This extra level of encoding is sometimes used -// when communicating with JavaScript programs: -// -//    Int64String int64 `json:",string"` -// -// The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, dollar signs, percent signs, hyphens, -// underscores and slashes. -// -// Anonymous struct fields are usually marshaled as if their inner exported fields -// were fields in the outer struct, subject to the usual Go visibility rules amended -// as described in the next paragraph. -// An anonymous struct field with a name given in its JSON tag is treated as -// having that name, rather than being anonymous. -// An anonymous struct field of interface type is treated the same as having -// that type as its name, rather than being anonymous. -// -// The Go visibility rules for struct fields are amended for JSON when -// deciding which field to marshal or unmarshal. If there are -// multiple fields at the same level, and that level is the least -// nested (and would therefore be the nesting level selected by the -// usual Go rules), the following extra rules apply: -// -// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, -// even if there are multiple untagged fields that would otherwise conflict. -// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. -// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. -// -// Handling of anonymous struct fields is new in Go 1.1. -// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of -// an anonymous struct field in both current and earlier versions, give the field -// a JSON tag of "-". -// -// Map values encode as JSON objects. The map's key type must either be a string -// or implement encoding.TextMarshaler.  The map keys are used as JSON object -// keys, subject to the UTF-8 coercion described for string values above. -// -// Pointer values encode as the value pointed to. -// A nil pointer encodes as the null JSON value. -// -// Interface values encode as the value contained in the interface. -// A nil interface value encodes as the null JSON value. -// -// Channel, complex, and function values cannot be encoded in JSON. -// Attempting to encode such a value causes Marshal to return -// an UnsupportedTypeError. -// -// JSON cannot represent cyclic data structures and Marshal does not -// handle them. Passing cyclic structures to Marshal will result in -// an infinite recursion. -// -func Marshal(v interface{}) ([]byte, error) { -	e := &encodeState{} -	err := e.marshal(v, encOpts{escapeHTML: true}) -	if err != nil { -		return nil, err -	} -	return e.Bytes(), nil -} - -// MarshalIndent is like Marshal but applies Indent to format the output. -func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { -	b, err := Marshal(v) -	if err != nil { -		return nil, err -	} -	var buf bytes.Buffer -	err = Indent(&buf, b, prefix, indent) -	if err != nil { -		return nil, err -	} -	return buf.Bytes(), nil -} - -// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 -// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 -// so that the JSON will be safe to embed inside HTML <script> tags. -// For historical reasons, web browsers don't honor standard HTML -// escaping within <script> tags, so an alternative JSON encoding must -// be used. -func HTMLEscape(dst *bytes.Buffer, src []byte) { -	// The characters can only appear in string literals, -	// so just scan the string one byte at a time. -	start := 0 -	for i, c := range src { -		if c == '<' || c == '>' || c == '&' { -			if start < i { -				dst.Write(src[start:i]) -			} -			dst.WriteString(`\u00`) -			dst.WriteByte(hex[c>>4]) -			dst.WriteByte(hex[c&0xF]) -			start = i + 1 -		} -		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). -		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { -			if start < i { -				dst.Write(src[start:i]) -			} -			dst.WriteString(`\u202`) -			dst.WriteByte(hex[src[i+2]&0xF]) -			start = i + 3 -		} -	} -	if start < len(src) { -		dst.Write(src[start:]) -	} -} - -// Marshaler is the interface implemented by types that -// can marshal themselves into valid JSON. -type Marshaler interface { -	MarshalJSON() ([]byte, error) -} - -// An UnsupportedTypeError is returned by Marshal when attempting -// to encode an unsupported value type. -type UnsupportedTypeError struct { -	Type reflect.Type -} - -func (e *UnsupportedTypeError) Error() string { -	return "json: unsupported type: " + e.Type.String() -} - -type UnsupportedValueError struct { -	Value reflect.Value -	Str   string -} - -func (e *UnsupportedValueError) Error() string { -	return "json: unsupported value: " + e.Str -} - -// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when -// attempting to encode a string value with invalid UTF-8 sequences. -// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by -// replacing invalid bytes with the Unicode replacement rune U+FFFD. -// This error is no longer generated but is kept for backwards compatibility -// with programs that might mention it. -type InvalidUTF8Error struct { -	S string // the whole string value that caused the error -} - -func (e *InvalidUTF8Error) Error() string { -	return "json: invalid UTF-8 in string: " + strconv.Quote(e.S) -} - -type MarshalerError struct { -	Type reflect.Type -	Err  error -} - -func (e *MarshalerError) Error() string { -	return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error() -} - -var hex = "0123456789abcdef" - -// An encodeState encodes JSON into a bytes.Buffer. -type encodeState struct { -	bytes.Buffer // accumulated output -	scratch      [64]byte -	ext          Extension -} - -var encodeStatePool sync.Pool - -func newEncodeState() *encodeState { -	if v := encodeStatePool.Get(); v != nil { -		e := v.(*encodeState) -		e.Reset() -		return e -	} -	return new(encodeState) -} - -func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) { -	defer func() { -		if r := recover(); r != nil { -			if _, ok := r.(runtime.Error); ok { -				panic(r) -			} -			if s, ok := r.(string); ok { -				panic(s) -			} -			err = r.(error) -		} -	}() -	e.reflectValue(reflect.ValueOf(v), opts) -	return nil -} - -func (e *encodeState) error(err error) { -	panic(err) -} - -func isEmptyValue(v reflect.Value) bool { -	switch v.Kind() { -	case reflect.Array, reflect.Map, reflect.Slice, reflect.String: -		return v.Len() == 0 -	case reflect.Bool: -		return !v.Bool() -	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -		return v.Int() == 0 -	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -		return v.Uint() == 0 -	case reflect.Float32, reflect.Float64: -		return v.Float() == 0 -	case reflect.Interface, reflect.Ptr: -		return v.IsNil() -	} -	return false -} - -func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { -	valueEncoder(v)(e, v, opts) -} - -type encOpts struct { -	// quoted causes primitive fields to be encoded inside JSON strings. -	quoted bool -	// escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. -	escapeHTML bool -} - -type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) - -var encoderCache struct { -	sync.RWMutex -	m map[reflect.Type]encoderFunc -} - -func valueEncoder(v reflect.Value) encoderFunc { -	if !v.IsValid() { -		return invalidValueEncoder -	} -	return typeEncoder(v.Type()) -} - -func typeEncoder(t reflect.Type) encoderFunc { -	encoderCache.RLock() -	f := encoderCache.m[t] -	encoderCache.RUnlock() -	if f != nil { -		return f -	} - -	// To deal with recursive types, populate the map with an -	// indirect func before we build it. This type waits on the -	// real func (f) to be ready and then calls it. This indirect -	// func is only used for recursive types. -	encoderCache.Lock() -	if encoderCache.m == nil { -		encoderCache.m = make(map[reflect.Type]encoderFunc) -	} -	var wg sync.WaitGroup -	wg.Add(1) -	encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) { -		wg.Wait() -		f(e, v, opts) -	} -	encoderCache.Unlock() - -	// Compute fields without lock. -	// Might duplicate effort but won't hold other computations back. -	innerf := newTypeEncoder(t, true) -	f = func(e *encodeState, v reflect.Value, opts encOpts) { -		encode, ok := e.ext.encode[v.Type()] -		if !ok { -			innerf(e, v, opts) -			return -		} - -		b, err := encode(v.Interface()) -		if err == nil { -			// copy JSON into buffer, checking validity. -			err = compact(&e.Buffer, b, opts.escapeHTML) -		} -		if err != nil { -			e.error(&MarshalerError{v.Type(), err}) -		} -	} -	wg.Done() -	encoderCache.Lock() -	encoderCache.m[t] = f -	encoderCache.Unlock() -	return f -} - -var ( -	marshalerType     = reflect.TypeOf(new(Marshaler)).Elem() -	textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem() -) - -// newTypeEncoder constructs an encoderFunc for a type. -// The returned encoder only checks CanAddr when allowAddr is true. -func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { -	if t.Implements(marshalerType) { -		return marshalerEncoder -	} -	if t.Kind() != reflect.Ptr && allowAddr { -		if reflect.PtrTo(t).Implements(marshalerType) { -			return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) -		} -	} - -	if t.Implements(textMarshalerType) { -		return textMarshalerEncoder -	} -	if t.Kind() != reflect.Ptr && allowAddr { -		if reflect.PtrTo(t).Implements(textMarshalerType) { -			return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) -		} -	} - -	switch t.Kind() { -	case reflect.Bool: -		return boolEncoder -	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: -		return intEncoder -	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: -		return uintEncoder -	case reflect.Float32: -		return float32Encoder -	case reflect.Float64: -		return float64Encoder -	case reflect.String: -		return stringEncoder -	case reflect.Interface: -		return interfaceEncoder -	case reflect.Struct: -		return newStructEncoder(t) -	case reflect.Map: -		return newMapEncoder(t) -	case reflect.Slice: -		return newSliceEncoder(t) -	case reflect.Array: -		return newArrayEncoder(t) -	case reflect.Ptr: -		return newPtrEncoder(t) -	default: -		return unsupportedTypeEncoder -	} -} - -func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) { -	e.WriteString("null") -} - -func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	if v.Kind() == reflect.Ptr && v.IsNil() { -		e.WriteString("null") -		return -	} -	m := v.Interface().(Marshaler) -	b, err := m.MarshalJSON() -	if err == nil { -		// copy JSON into buffer, checking validity. -		err = compact(&e.Buffer, b, opts.escapeHTML) -	} -	if err != nil { -		e.error(&MarshalerError{v.Type(), err}) -	} -} - -func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) { -	va := v.Addr() -	if va.IsNil() { -		e.WriteString("null") -		return -	} -	m := va.Interface().(Marshaler) -	b, err := m.MarshalJSON() -	if err == nil { -		// copy JSON into buffer, checking validity. -		err = compact(&e.Buffer, b, true) -	} -	if err != nil { -		e.error(&MarshalerError{v.Type(), err}) -	} -} - -func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	if v.Kind() == reflect.Ptr && v.IsNil() { -		e.WriteString("null") -		return -	} -	m := v.Interface().(encoding.TextMarshaler) -	b, err := m.MarshalText() -	if err != nil { -		e.error(&MarshalerError{v.Type(), err}) -	} -	e.stringBytes(b, opts.escapeHTML) -} - -func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	va := v.Addr() -	if va.IsNil() { -		e.WriteString("null") -		return -	} -	m := va.Interface().(encoding.TextMarshaler) -	b, err := m.MarshalText() -	if err != nil { -		e.error(&MarshalerError{v.Type(), err}) -	} -	e.stringBytes(b, opts.escapeHTML) -} - -func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	if opts.quoted { -		e.WriteByte('"') -	} -	if v.Bool() { -		e.WriteString("true") -	} else { -		e.WriteString("false") -	} -	if opts.quoted { -		e.WriteByte('"') -	} -} - -func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	b := strconv.AppendInt(e.scratch[:0], v.Int(), 10) -	if opts.quoted { -		e.WriteByte('"') -	} -	e.Write(b) -	if opts.quoted { -		e.WriteByte('"') -	} -} - -func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10) -	if opts.quoted { -		e.WriteByte('"') -	} -	e.Write(b) -	if opts.quoted { -		e.WriteByte('"') -	} -} - -type floatEncoder int // number of bits - -func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	f := v.Float() -	if math.IsInf(f, 0) || math.IsNaN(f) { -		e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))}) -	} -	b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits)) -	if opts.quoted { -		e.WriteByte('"') -	} -	e.Write(b) -	if opts.quoted { -		e.WriteByte('"') -	} -} - -var ( -	float32Encoder = (floatEncoder(32)).encode -	float64Encoder = (floatEncoder(64)).encode -) - -func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	if v.Type() == numberType { -		numStr := v.String() -		// In Go1.5 the empty string encodes to "0", while this is not a valid number literal -		// we keep compatibility so check validity after this. -		if numStr == "" { -			numStr = "0" // Number's zero-val -		} -		if !isValidNumber(numStr) { -			e.error(fmt.Errorf("json: invalid number literal %q", numStr)) -		} -		e.WriteString(numStr) -		return -	} -	if opts.quoted { -		sb, err := Marshal(v.String()) -		if err != nil { -			e.error(err) -		} -		e.string(string(sb), opts.escapeHTML) -	} else { -		e.string(v.String(), opts.escapeHTML) -	} -} - -func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { -	if v.IsNil() { -		e.WriteString("null") -		return -	} -	e.reflectValue(v.Elem(), opts) -} - -func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { -	e.error(&UnsupportedTypeError{v.Type()}) -} - -type structEncoder struct { -	fields    []field -	fieldEncs []encoderFunc -} - -func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	e.WriteByte('{') -	first := true -	for i, f := range se.fields { -		fv := fieldByIndex(v, f.index) -		if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) { -			continue -		} -		if first { -			first = false -		} else { -			e.WriteByte(',') -		} -		e.string(f.name, opts.escapeHTML) -		e.WriteByte(':') -		opts.quoted = f.quoted -		se.fieldEncs[i](e, fv, opts) -	} -	e.WriteByte('}') -} - -func newStructEncoder(t reflect.Type) encoderFunc { -	fields := cachedTypeFields(t) -	se := &structEncoder{ -		fields:    fields, -		fieldEncs: make([]encoderFunc, len(fields)), -	} -	for i, f := range fields { -		se.fieldEncs[i] = typeEncoder(typeByIndex(t, f.index)) -	} -	return se.encode -} - -type mapEncoder struct { -	elemEnc encoderFunc -} - -func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	if v.IsNil() { -		e.WriteString("null") -		return -	} -	e.WriteByte('{') - -	// Extract and sort the keys. -	keys := v.MapKeys() -	sv := make([]reflectWithString, len(keys)) -	for i, v := range keys { -		sv[i].v = v -		if err := sv[i].resolve(); err != nil { -			e.error(&MarshalerError{v.Type(), err}) -		} -	} -	sort.Sort(byString(sv)) - -	for i, kv := range sv { -		if i > 0 { -			e.WriteByte(',') -		} -		e.string(kv.s, opts.escapeHTML) -		e.WriteByte(':') -		me.elemEnc(e, v.MapIndex(kv.v), opts) -	} -	e.WriteByte('}') -} - -func newMapEncoder(t reflect.Type) encoderFunc { -	if t.Key().Kind() != reflect.String && !t.Key().Implements(textMarshalerType) { -		return unsupportedTypeEncoder -	} -	me := &mapEncoder{typeEncoder(t.Elem())} -	return me.encode -} - -func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) { -	if v.IsNil() { -		e.WriteString("null") -		return -	} -	s := v.Bytes() -	e.WriteByte('"') -	if len(s) < 1024 { -		// for small buffers, using Encode directly is much faster. -		dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) -		base64.StdEncoding.Encode(dst, s) -		e.Write(dst) -	} else { -		// for large buffers, avoid unnecessary extra temporary -		// buffer space. -		enc := base64.NewEncoder(base64.StdEncoding, e) -		enc.Write(s) -		enc.Close() -	} -	e.WriteByte('"') -} - -// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil. -type sliceEncoder struct { -	arrayEnc encoderFunc -} - -func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	if v.IsNil() { -		e.WriteString("null") -		return -	} -	se.arrayEnc(e, v, opts) -} - -func newSliceEncoder(t reflect.Type) encoderFunc { -	// Byte slices get special treatment; arrays don't. -	if t.Elem().Kind() == reflect.Uint8 && -		!t.Elem().Implements(marshalerType) && -		!t.Elem().Implements(textMarshalerType) { -		return encodeByteSlice -	} -	enc := &sliceEncoder{newArrayEncoder(t)} -	return enc.encode -} - -type arrayEncoder struct { -	elemEnc encoderFunc -} - -func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	e.WriteByte('[') -	n := v.Len() -	for i := 0; i < n; i++ { -		if i > 0 { -			e.WriteByte(',') -		} -		ae.elemEnc(e, v.Index(i), opts) -	} -	e.WriteByte(']') -} - -func newArrayEncoder(t reflect.Type) encoderFunc { -	enc := &arrayEncoder{typeEncoder(t.Elem())} -	return enc.encode -} - -type ptrEncoder struct { -	elemEnc encoderFunc -} - -func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	if v.IsNil() { -		e.WriteString("null") -		return -	} -	pe.elemEnc(e, v.Elem(), opts) -} - -func newPtrEncoder(t reflect.Type) encoderFunc { -	enc := &ptrEncoder{typeEncoder(t.Elem())} -	return enc.encode -} - -type condAddrEncoder struct { -	canAddrEnc, elseEnc encoderFunc -} - -func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { -	if v.CanAddr() { -		ce.canAddrEnc(e, v, opts) -	} else { -		ce.elseEnc(e, v, opts) -	} -} - -// newCondAddrEncoder returns an encoder that checks whether its value -// CanAddr and delegates to canAddrEnc if so, else to elseEnc. -func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc { -	enc := &condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} -	return enc.encode -} - -func isValidTag(s string) bool { -	if s == "" { -		return false -	} -	for _, c := range s { -		switch { -		case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): -			// Backslash and quote chars are reserved, but -			// otherwise any punctuation chars are allowed -			// in a tag name. -		default: -			if !unicode.IsLetter(c) && !unicode.IsDigit(c) { -				return false -			} -		} -	} -	return true -} - -func fieldByIndex(v reflect.Value, index []int) reflect.Value { -	for _, i := range index { -		if v.Kind() == reflect.Ptr { -			if v.IsNil() { -				return reflect.Value{} -			} -			v = v.Elem() -		} -		v = v.Field(i) -	} -	return v -} - -func typeByIndex(t reflect.Type, index []int) reflect.Type { -	for _, i := range index { -		if t.Kind() == reflect.Ptr { -			t = t.Elem() -		} -		t = t.Field(i).Type -	} -	return t -} - -type reflectWithString struct { -	v reflect.Value -	s string -} - -func (w *reflectWithString) resolve() error { -	if w.v.Kind() == reflect.String { -		w.s = w.v.String() -		return nil -	} -	buf, err := w.v.Interface().(encoding.TextMarshaler).MarshalText() -	w.s = string(buf) -	return err -} - -// byString is a slice of reflectWithString where the reflect.Value is either -// a string or an encoding.TextMarshaler. -// It implements the methods to sort by string. -type byString []reflectWithString - -func (sv byString) Len() int           { return len(sv) } -func (sv byString) Swap(i, j int)      { sv[i], sv[j] = sv[j], sv[i] } -func (sv byString) Less(i, j int) bool { return sv[i].s < sv[j].s } - -// NOTE: keep in sync with stringBytes below. -func (e *encodeState) string(s string, escapeHTML bool) int { -	len0 := e.Len() -	e.WriteByte('"') -	start := 0 -	for i := 0; i < len(s); { -		if b := s[i]; b < utf8.RuneSelf { -			if 0x20 <= b && b != '\\' && b != '"' && -				(!escapeHTML || b != '<' && b != '>' && b != '&') { -				i++ -				continue -			} -			if start < i { -				e.WriteString(s[start:i]) -			} -			switch b { -			case '\\', '"': -				e.WriteByte('\\') -				e.WriteByte(b) -			case '\n': -				e.WriteByte('\\') -				e.WriteByte('n') -			case '\r': -				e.WriteByte('\\') -				e.WriteByte('r') -			case '\t': -				e.WriteByte('\\') -				e.WriteByte('t') -			default: -				// This encodes bytes < 0x20 except for \t, \n and \r. -				// If escapeHTML is set, it also escapes <, >, and & -				// because they can lead to security holes when -				// user-controlled strings are rendered into JSON -				// and served to some browsers. -				e.WriteString(`\u00`) -				e.WriteByte(hex[b>>4]) -				e.WriteByte(hex[b&0xF]) -			} -			i++ -			start = i -			continue -		} -		c, size := utf8.DecodeRuneInString(s[i:]) -		if c == utf8.RuneError && size == 1 { -			if start < i { -				e.WriteString(s[start:i]) -			} -			e.WriteString(`\ufffd`) -			i += size -			start = i -			continue -		} -		// U+2028 is LINE SEPARATOR. -		// U+2029 is PARAGRAPH SEPARATOR. -		// They are both technically valid characters in JSON strings, -		// but don't work in JSONP, which has to be evaluated as JavaScript, -		// and can lead to security holes there. It is valid JSON to -		// escape them, so we do so unconditionally. -		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. -		if c == '\u2028' || c == '\u2029' { -			if start < i { -				e.WriteString(s[start:i]) -			} -			e.WriteString(`\u202`) -			e.WriteByte(hex[c&0xF]) -			i += size -			start = i -			continue -		} -		i += size -	} -	if start < len(s) { -		e.WriteString(s[start:]) -	} -	e.WriteByte('"') -	return e.Len() - len0 -} - -// NOTE: keep in sync with string above. -func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int { -	len0 := e.Len() -	e.WriteByte('"') -	start := 0 -	for i := 0; i < len(s); { -		if b := s[i]; b < utf8.RuneSelf { -			if 0x20 <= b && b != '\\' && b != '"' && -				(!escapeHTML || b != '<' && b != '>' && b != '&') { -				i++ -				continue -			} -			if start < i { -				e.Write(s[start:i]) -			} -			switch b { -			case '\\', '"': -				e.WriteByte('\\') -				e.WriteByte(b) -			case '\n': -				e.WriteByte('\\') -				e.WriteByte('n') -			case '\r': -				e.WriteByte('\\') -				e.WriteByte('r') -			case '\t': -				e.WriteByte('\\') -				e.WriteByte('t') -			default: -				// This encodes bytes < 0x20 except for \t, \n and \r. -				// If escapeHTML is set, it also escapes <, >, and & -				// because they can lead to security holes when -				// user-controlled strings are rendered into JSON -				// and served to some browsers. -				e.WriteString(`\u00`) -				e.WriteByte(hex[b>>4]) -				e.WriteByte(hex[b&0xF]) -			} -			i++ -			start = i -			continue -		} -		c, size := utf8.DecodeRune(s[i:]) -		if c == utf8.RuneError && size == 1 { -			if start < i { -				e.Write(s[start:i]) -			} -			e.WriteString(`\ufffd`) -			i += size -			start = i -			continue -		} -		// U+2028 is LINE SEPARATOR. -		// U+2029 is PARAGRAPH SEPARATOR. -		// They are both technically valid characters in JSON strings, -		// but don't work in JSONP, which has to be evaluated as JavaScript, -		// and can lead to security holes there. It is valid JSON to -		// escape them, so we do so unconditionally. -		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. -		if c == '\u2028' || c == '\u2029' { -			if start < i { -				e.Write(s[start:i]) -			} -			e.WriteString(`\u202`) -			e.WriteByte(hex[c&0xF]) -			i += size -			start = i -			continue -		} -		i += size -	} -	if start < len(s) { -		e.Write(s[start:]) -	} -	e.WriteByte('"') -	return e.Len() - len0 -} - -// A field represents a single field found in a struct. -type field struct { -	name      string -	nameBytes []byte                 // []byte(name) -	equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent - -	tag       bool -	index     []int -	typ       reflect.Type -	omitEmpty bool -	quoted    bool -} - -func fillField(f field) field { -	f.nameBytes = []byte(f.name) -	f.equalFold = foldFunc(f.nameBytes) -	return f -} - -// byName sorts field by name, breaking ties with depth, -// then breaking ties with "name came from json tag", then -// breaking ties with index sequence. -type byName []field - -func (x byName) Len() int { return len(x) } - -func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byName) Less(i, j int) bool { -	if x[i].name != x[j].name { -		return x[i].name < x[j].name -	} -	if len(x[i].index) != len(x[j].index) { -		return len(x[i].index) < len(x[j].index) -	} -	if x[i].tag != x[j].tag { -		return x[i].tag -	} -	return byIndex(x).Less(i, j) -} - -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { -	for k, xik := range x[i].index { -		if k >= len(x[j].index) { -			return false -		} -		if xik != x[j].index[k] { -			return xik < x[j].index[k] -		} -	} -	return len(x[i].index) < len(x[j].index) -} - -// typeFields returns a list of fields that JSON should recognize for the given type. -// The algorithm is breadth-first search over the set of structs to include - the top struct -// and then any reachable anonymous structs. -func typeFields(t reflect.Type) []field { -	// Anonymous fields to explore at the current level and the next. -	current := []field{} -	next := []field{{typ: t}} - -	// Count of queued names for current level and the next. -	count := map[reflect.Type]int{} -	nextCount := map[reflect.Type]int{} - -	// Types already visited at an earlier level. -	visited := map[reflect.Type]bool{} - -	// Fields found. -	var fields []field - -	for len(next) > 0 { -		current, next = next, current[:0] -		count, nextCount = nextCount, map[reflect.Type]int{} - -		for _, f := range current { -			if visited[f.typ] { -				continue -			} -			visited[f.typ] = true - -			// Scan f.typ for fields to include. -			for i := 0; i < f.typ.NumField(); i++ { -				sf := f.typ.Field(i) -				if sf.PkgPath != "" && !sf.Anonymous { // unexported -					continue -				} -				tag := sf.Tag.Get("json") -				if tag == "-" { -					continue -				} -				name, opts := parseTag(tag) -				if !isValidTag(name) { -					name = "" -				} -				index := make([]int, len(f.index)+1) -				copy(index, f.index) -				index[len(f.index)] = i - -				ft := sf.Type -				if ft.Name() == "" && ft.Kind() == reflect.Ptr { -					// Follow pointer. -					ft = ft.Elem() -				} - -				// Only strings, floats, integers, and booleans can be quoted. -				quoted := false -				if opts.Contains("string") { -					switch ft.Kind() { -					case reflect.Bool, -						reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, -						reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, -						reflect.Float32, reflect.Float64, -						reflect.String: -						quoted = true -					} -				} - -				// Record found field and index sequence. -				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { -					tagged := name != "" -					if name == "" { -						name = sf.Name -					} -					fields = append(fields, fillField(field{ -						name:      name, -						tag:       tagged, -						index:     index, -						typ:       ft, -						omitEmpty: opts.Contains("omitempty"), -						quoted:    quoted, -					})) -					if count[f.typ] > 1 { -						// If there were multiple instances, add a second, -						// so that the annihilation code will see a duplicate. -						// It only cares about the distinction between 1 or 2, -						// so don't bother generating any more copies. -						fields = append(fields, fields[len(fields)-1]) -					} -					continue -				} - -				// Record new anonymous struct to explore in next round. -				nextCount[ft]++ -				if nextCount[ft] == 1 { -					next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) -				} -			} -		} -	} - -	sort.Sort(byName(fields)) - -	// Delete all fields that are hidden by the Go rules for embedded fields, -	// except that fields with JSON tags are promoted. - -	// The fields are sorted in primary order of name, secondary order -	// of field index length. Loop over names; for each name, delete -	// hidden fields by choosing the one dominant field that survives. -	out := fields[:0] -	for advance, i := 0, 0; i < len(fields); i += advance { -		// One iteration per name. -		// Find the sequence of fields with the name of this first field. -		fi := fields[i] -		name := fi.name -		for advance = 1; i+advance < len(fields); advance++ { -			fj := fields[i+advance] -			if fj.name != name { -				break -			} -		} -		if advance == 1 { // Only one field with this name -			out = append(out, fi) -			continue -		} -		dominant, ok := dominantField(fields[i : i+advance]) -		if ok { -			out = append(out, dominant) -		} -	} - -	fields = out -	sort.Sort(byIndex(fields)) - -	return fields -} - -// dominantField looks through the fields, all of which are known to -// have the same name, to find the single field that dominates the -// others using Go's embedding rules, modified by the presence of -// JSON tags. If there are multiple top-level fields, the boolean -// will be false: This condition is an error in Go and we skip all -// the fields. -func dominantField(fields []field) (field, bool) { -	// The fields are sorted in increasing index-length order. The winner -	// must therefore be one with the shortest index length. Drop all -	// longer entries, which is easy: just truncate the slice. -	length := len(fields[0].index) -	tagged := -1 // Index of first tagged field. -	for i, f := range fields { -		if len(f.index) > length { -			fields = fields[:i] -			break -		} -		if f.tag { -			if tagged >= 0 { -				// Multiple tagged fields at the same level: conflict. -				// Return no field. -				return field{}, false -			} -			tagged = i -		} -	} -	if tagged >= 0 { -		return fields[tagged], true -	} -	// All remaining fields have the same length. If there's more than one, -	// we have a conflict (two fields named "X" at the same level) and we -	// return no field. -	if len(fields) > 1 { -		return field{}, false -	} -	return fields[0], true -} - -var fieldCache struct { -	sync.RWMutex -	m map[reflect.Type][]field -} - -// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) []field { -	fieldCache.RLock() -	f := fieldCache.m[t] -	fieldCache.RUnlock() -	if f != nil { -		return f -	} - -	// Compute fields without lock. -	// Might duplicate effort but won't hold other computations back. -	f = typeFields(t) -	if f == nil { -		f = []field{} -	} - -	fieldCache.Lock() -	if fieldCache.m == nil { -		fieldCache.m = map[reflect.Type][]field{} -	} -	fieldCache.m[t] = f -	fieldCache.Unlock() -	return f -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/extension.go b/vendor/gopkg.in/mgo.v2/internal/json/extension.go deleted file mode 100644 index 1c8fd45..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/extension.go +++ /dev/null @@ -1,95 +0,0 @@ -package json - -import ( -	"reflect" -) - -// Extension holds a set of additional rules to be used when unmarshaling -// strict JSON or JSON-like content. -type Extension struct { -	funcs  map[string]funcExt -	consts map[string]interface{} -	keyed  map[string]func([]byte) (interface{}, error) -	encode map[reflect.Type]func(v interface{}) ([]byte, error) - -	unquotedKeys   bool -	trailingCommas bool -} - -type funcExt struct { -	key  string -	args []string -} - -// Extend changes the decoder behavior to consider the provided extension. -func (dec *Decoder) Extend(ext *Extension) { dec.d.ext = *ext } - -// Extend changes the encoder behavior to consider the provided extension. -func (enc *Encoder) Extend(ext *Extension) { enc.ext = *ext } - -// Extend includes in e the extensions defined in ext. -func (e *Extension) Extend(ext *Extension) { -	for name, fext := range ext.funcs { -		e.DecodeFunc(name, fext.key, fext.args...) -	} -	for name, value := range ext.consts { -		e.DecodeConst(name, value) -	} -	for key, decode := range ext.keyed { -		e.DecodeKeyed(key, decode) -	} -	for typ, encode := range ext.encode { -		if e.encode == nil { -			e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error)) -		} -		e.encode[typ] = encode -	} -} - -// DecodeFunc defines a function call that may be observed inside JSON content. -// A function with the provided name will be unmarshaled as the document -// {key: {args[0]: ..., args[N]: ...}}. -func (e *Extension) DecodeFunc(name string, key string, args ...string) { -	if e.funcs == nil { -		e.funcs = make(map[string]funcExt) -	} -	e.funcs[name] = funcExt{key, args} -} - -// DecodeConst defines a constant name that may be observed inside JSON content -// and will be decoded with the provided value. -func (e *Extension) DecodeConst(name string, value interface{}) { -	if e.consts == nil { -		e.consts = make(map[string]interface{}) -	} -	e.consts[name] = value -} - -// DecodeKeyed defines a key that when observed as the first element inside a -// JSON document triggers the decoding of that document via the provided -// decode function. -func (e *Extension) DecodeKeyed(key string, decode func(data []byte) (interface{}, error)) { -	if e.keyed == nil { -		e.keyed = make(map[string]func([]byte) (interface{}, error)) -	} -	e.keyed[key] = decode -} - -// DecodeUnquotedKeys defines whether to accept map keys that are unquoted strings. -func (e *Extension) DecodeUnquotedKeys(accept bool) { -	e.unquotedKeys = accept -} - -// DecodeTrailingCommas defines whether to accept trailing commas in maps and arrays. -func (e *Extension) DecodeTrailingCommas(accept bool) { -	e.trailingCommas = accept -} - -// EncodeType registers a function to encode values with the same type of the -// provided sample. -func (e *Extension) EncodeType(sample interface{}, encode func(v interface{}) ([]byte, error)) { -	if e.encode == nil { -		e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error)) -	} -	e.encode[reflect.TypeOf(sample)] = encode -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/fold.go b/vendor/gopkg.in/mgo.v2/internal/json/fold.go deleted file mode 100644 index 9e17012..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/fold.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( -	"bytes" -	"unicode/utf8" -) - -const ( -	caseMask     = ^byte(0x20) // Mask to ignore case in ASCII. -	kelvin       = '\u212a' -	smallLongEss = '\u017f' -) - -// foldFunc returns one of four different case folding equivalence -// functions, from most general (and slow) to fastest: -// -// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 -// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') -// 3) asciiEqualFold, no special, but includes non-letters (including _) -// 4) simpleLetterEqualFold, no specials, no non-letters. -// -// The letters S and K are special because they map to 3 runes, not just 2: -//  * S maps to s and to U+017F 'ſ' Latin small letter long s -//  * k maps to K and to U+212A 'K' Kelvin sign -// See https://play.golang.org/p/tTxjOc0OGo -// -// The returned function is specialized for matching against s and -// should only be given s. It's not curried for performance reasons. -func foldFunc(s []byte) func(s, t []byte) bool { -	nonLetter := false -	special := false // special letter -	for _, b := range s { -		if b >= utf8.RuneSelf { -			return bytes.EqualFold -		} -		upper := b & caseMask -		if upper < 'A' || upper > 'Z' { -			nonLetter = true -		} else if upper == 'K' || upper == 'S' { -			// See above for why these letters are special. -			special = true -		} -	} -	if special { -		return equalFoldRight -	} -	if nonLetter { -		return asciiEqualFold -	} -	return simpleLetterEqualFold -} - -// equalFoldRight is a specialization of bytes.EqualFold when s is -// known to be all ASCII (including punctuation), but contains an 's', -// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. -// See comments on foldFunc. -func equalFoldRight(s, t []byte) bool { -	for _, sb := range s { -		if len(t) == 0 { -			return false -		} -		tb := t[0] -		if tb < utf8.RuneSelf { -			if sb != tb { -				sbUpper := sb & caseMask -				if 'A' <= sbUpper && sbUpper <= 'Z' { -					if sbUpper != tb&caseMask { -						return false -					} -				} else { -					return false -				} -			} -			t = t[1:] -			continue -		} -		// sb is ASCII and t is not. t must be either kelvin -		// sign or long s; sb must be s, S, k, or K. -		tr, size := utf8.DecodeRune(t) -		switch sb { -		case 's', 'S': -			if tr != smallLongEss { -				return false -			} -		case 'k', 'K': -			if tr != kelvin { -				return false -			} -		default: -			return false -		} -		t = t[size:] - -	} -	if len(t) > 0 { -		return false -	} -	return true -} - -// asciiEqualFold is a specialization of bytes.EqualFold for use when -// s is all ASCII (but may contain non-letters) and contains no -// special-folding letters. -// See comments on foldFunc. -func asciiEqualFold(s, t []byte) bool { -	if len(s) != len(t) { -		return false -	} -	for i, sb := range s { -		tb := t[i] -		if sb == tb { -			continue -		} -		if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { -			if sb&caseMask != tb&caseMask { -				return false -			} -		} else { -			return false -		} -	} -	return true -} - -// simpleLetterEqualFold is a specialization of bytes.EqualFold for -// use when s is all ASCII letters (no underscores, etc) and also -// doesn't contain 'k', 'K', 's', or 'S'. -// See comments on foldFunc. -func simpleLetterEqualFold(s, t []byte) bool { -	if len(s) != len(t) { -		return false -	} -	for i, b := range s { -		if b&caseMask != t[i]&caseMask { -			return false -		} -	} -	return true -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/indent.go b/vendor/gopkg.in/mgo.v2/internal/json/indent.go deleted file mode 100644 index fba1954..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/indent.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import "bytes" - -// Compact appends to dst the JSON-encoded src with -// insignificant space characters elided. -func Compact(dst *bytes.Buffer, src []byte) error { -	return compact(dst, src, false) -} - -func compact(dst *bytes.Buffer, src []byte, escape bool) error { -	origLen := dst.Len() -	var scan scanner -	scan.reset() -	start := 0 -	for i, c := range src { -		if escape && (c == '<' || c == '>' || c == '&') { -			if start < i { -				dst.Write(src[start:i]) -			} -			dst.WriteString(`\u00`) -			dst.WriteByte(hex[c>>4]) -			dst.WriteByte(hex[c&0xF]) -			start = i + 1 -		} -		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9). -		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 { -			if start < i { -				dst.Write(src[start:i]) -			} -			dst.WriteString(`\u202`) -			dst.WriteByte(hex[src[i+2]&0xF]) -			start = i + 3 -		} -		v := scan.step(&scan, c) -		if v >= scanSkipSpace { -			if v == scanError { -				break -			} -			if start < i { -				dst.Write(src[start:i]) -			} -			start = i + 1 -		} -	} -	if scan.eof() == scanError { -		dst.Truncate(origLen) -		return scan.err -	} -	if start < len(src) { -		dst.Write(src[start:]) -	} -	return nil -} - -func newline(dst *bytes.Buffer, prefix, indent string, depth int) { -	dst.WriteByte('\n') -	dst.WriteString(prefix) -	for i := 0; i < depth; i++ { -		dst.WriteString(indent) -	} -} - -// Indent appends to dst an indented form of the JSON-encoded src. -// Each element in a JSON object or array begins on a new, -// indented line beginning with prefix followed by one or more -// copies of indent according to the indentation nesting. -// The data appended to dst does not begin with the prefix nor -// any indentation, to make it easier to embed inside other formatted JSON data. -// Although leading space characters (space, tab, carriage return, newline) -// at the beginning of src are dropped, trailing space characters -// at the end of src are preserved and copied to dst. -// For example, if src has no trailing spaces, neither will dst; -// if src ends in a trailing newline, so will dst. -func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { -	origLen := dst.Len() -	var scan scanner -	scan.reset() -	needIndent := false -	depth := 0 -	for _, c := range src { -		scan.bytes++ -		v := scan.step(&scan, c) -		if v == scanSkipSpace { -			continue -		} -		if v == scanError { -			break -		} -		if needIndent && v != scanEndObject && v != scanEndArray { -			needIndent = false -			depth++ -			newline(dst, prefix, indent, depth) -		} - -		// Emit semantically uninteresting bytes -		// (in particular, punctuation in strings) unmodified. -		if v == scanContinue { -			dst.WriteByte(c) -			continue -		} - -		// Add spacing around real punctuation. -		switch c { -		case '{', '[': -			// delay indent so that empty object and array are formatted as {} and []. -			needIndent = true -			dst.WriteByte(c) - -		case ',': -			dst.WriteByte(c) -			newline(dst, prefix, indent, depth) - -		case ':': -			dst.WriteByte(c) -			dst.WriteByte(' ') - -		case '}', ']': -			if needIndent { -				// suppress indent in empty object/array -				needIndent = false -			} else { -				depth-- -				newline(dst, prefix, indent, depth) -			} -			dst.WriteByte(c) - -		default: -			dst.WriteByte(c) -		} -	} -	if scan.eof() == scanError { -		dst.Truncate(origLen) -		return scan.err -	} -	return nil -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/scanner.go b/vendor/gopkg.in/mgo.v2/internal/json/scanner.go deleted file mode 100644 index 9708043..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/scanner.go +++ /dev/null @@ -1,697 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -// JSON value parser state machine. -// Just about at the limit of what is reasonable to write by hand. -// Some parts are a bit tedious, but overall it nicely factors out the -// otherwise common code from the multiple scanning functions -// in this package (Compact, Indent, checkValid, nextValue, etc). -// -// This file starts with two simple examples using the scanner -// before diving into the scanner itself. - -import "strconv" - -// checkValid verifies that data is valid JSON-encoded data. -// scan is passed in for use by checkValid to avoid an allocation. -func checkValid(data []byte, scan *scanner) error { -	scan.reset() -	for _, c := range data { -		scan.bytes++ -		if scan.step(scan, c) == scanError { -			return scan.err -		} -	} -	if scan.eof() == scanError { -		return scan.err -	} -	return nil -} - -// nextValue splits data after the next whole JSON value, -// returning that value and the bytes that follow it as separate slices. -// scan is passed in for use by nextValue to avoid an allocation. -func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) { -	scan.reset() -	for i, c := range data { -		v := scan.step(scan, c) -		if v >= scanEndObject { -			switch v { -			// probe the scanner with a space to determine whether we will -			// get scanEnd on the next character. Otherwise, if the next character -			// is not a space, scanEndTop allocates a needless error. -			case scanEndObject, scanEndArray, scanEndParams: -				if scan.step(scan, ' ') == scanEnd { -					return data[:i+1], data[i+1:], nil -				} -			case scanError: -				return nil, nil, scan.err -			case scanEnd: -				return data[:i], data[i:], nil -			} -		} -	} -	if scan.eof() == scanError { -		return nil, nil, scan.err -	} -	return data, nil, nil -} - -// A SyntaxError is a description of a JSON syntax error. -type SyntaxError struct { -	msg    string // description of error -	Offset int64  // error occurred after reading Offset bytes -} - -func (e *SyntaxError) Error() string { return e.msg } - -// A scanner is a JSON scanning state machine. -// Callers call scan.reset() and then pass bytes in one at a time -// by calling scan.step(&scan, c) for each byte. -// The return value, referred to as an opcode, tells the -// caller about significant parsing events like beginning -// and ending literals, objects, and arrays, so that the -// caller can follow along if it wishes. -// The return value scanEnd indicates that a single top-level -// JSON value has been completed, *before* the byte that -// just got passed in.  (The indication must be delayed in order -// to recognize the end of numbers: is 123 a whole value or -// the beginning of 12345e+6?). -type scanner struct { -	// The step is a func to be called to execute the next transition. -	// Also tried using an integer constant and a single func -	// with a switch, but using the func directly was 10% faster -	// on a 64-bit Mac Mini, and it's nicer to read. -	step func(*scanner, byte) int - -	// Reached end of top-level value. -	endTop bool - -	// Stack of what we're in the middle of - array values, object keys, object values. -	parseState []int - -	// Error that happened, if any. -	err error - -	// 1-byte redo (see undo method) -	redo      bool -	redoCode  int -	redoState func(*scanner, byte) int - -	// total bytes consumed, updated by decoder.Decode -	bytes int64 -} - -// These values are returned by the state transition functions -// assigned to scanner.state and the method scanner.eof. -// They give details about the current state of the scan that -// callers might be interested to know about. -// It is okay to ignore the return value of any particular -// call to scanner.state: if one call returns scanError, -// every subsequent call will return scanError too. -const ( -	// Continue. -	scanContinue     = iota // uninteresting byte -	scanBeginLiteral        // end implied by next result != scanContinue -	scanBeginObject         // begin object -	scanObjectKey           // just finished object key (string) -	scanObjectValue         // just finished non-last object value -	scanEndObject           // end object (implies scanObjectValue if possible) -	scanBeginArray          // begin array -	scanArrayValue          // just finished array value -	scanEndArray            // end array (implies scanArrayValue if possible) -	scanBeginName           // begin function call -	scanParam               // begin function argument -	scanEndParams           // end function call -	scanSkipSpace           // space byte; can skip; known to be last "continue" result - -	// Stop. -	scanEnd   // top-level value ended *before* this byte; known to be first "stop" result -	scanError // hit an error, scanner.err. -) - -// These values are stored in the parseState stack. -// They give the current state of a composite value -// being scanned. If the parser is inside a nested value -// the parseState describes the nested state, outermost at entry 0. -const ( -	parseObjectKey   = iota // parsing object key (before colon) -	parseObjectValue        // parsing object value (after colon) -	parseArrayValue         // parsing array value -	parseName               // parsing unquoted name -	parseParam              // parsing function argument value -) - -// reset prepares the scanner for use. -// It must be called before calling s.step. -func (s *scanner) reset() { -	s.step = stateBeginValue -	s.parseState = s.parseState[0:0] -	s.err = nil -	s.redo = false -	s.endTop = false -} - -// eof tells the scanner that the end of input has been reached. -// It returns a scan status just as s.step does. -func (s *scanner) eof() int { -	if s.err != nil { -		return scanError -	} -	if s.endTop { -		return scanEnd -	} -	s.step(s, ' ') -	if s.endTop { -		return scanEnd -	} -	if s.err == nil { -		s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} -	} -	return scanError -} - -// pushParseState pushes a new parse state p onto the parse stack. -func (s *scanner) pushParseState(p int) { -	s.parseState = append(s.parseState, p) -} - -// popParseState pops a parse state (already obtained) off the stack -// and updates s.step accordingly. -func (s *scanner) popParseState() { -	n := len(s.parseState) - 1 -	s.parseState = s.parseState[0:n] -	s.redo = false -	if n == 0 { -		s.step = stateEndTop -		s.endTop = true -	} else { -		s.step = stateEndValue -	} -} - -func isSpace(c byte) bool { -	return c == ' ' || c == '\t' || c == '\r' || c == '\n' -} - -// stateBeginValueOrEmpty is the state after reading `[`. -func stateBeginValueOrEmpty(s *scanner, c byte) int { -	if c <= ' ' && isSpace(c) { -		return scanSkipSpace -	} -	if c == ']' { -		return stateEndValue(s, c) -	} -	return stateBeginValue(s, c) -} - -// stateBeginValue is the state at the beginning of the input. -func stateBeginValue(s *scanner, c byte) int { -	if c <= ' ' && isSpace(c) { -		return scanSkipSpace -	} -	switch c { -	case '{': -		s.step = stateBeginStringOrEmpty -		s.pushParseState(parseObjectKey) -		return scanBeginObject -	case '[': -		s.step = stateBeginValueOrEmpty -		s.pushParseState(parseArrayValue) -		return scanBeginArray -	case '"': -		s.step = stateInString -		return scanBeginLiteral -	case '-': -		s.step = stateNeg -		return scanBeginLiteral -	case '0': // beginning of 0.123 -		s.step = state0 -		return scanBeginLiteral -	case 'n': -		s.step = stateNew0 -		return scanBeginName -	} -	if '1' <= c && c <= '9' { // beginning of 1234.5 -		s.step = state1 -		return scanBeginLiteral -	} -	if isName(c) { -		s.step = stateName -		return scanBeginName -	} -	return s.error(c, "looking for beginning of value") -} - -func isName(c byte) bool { -	return c == '$' || c == '_' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' -} - -// stateBeginStringOrEmpty is the state after reading `{`. -func stateBeginStringOrEmpty(s *scanner, c byte) int { -	if c <= ' ' && isSpace(c) { -		return scanSkipSpace -	} -	if c == '}' { -		n := len(s.parseState) -		s.parseState[n-1] = parseObjectValue -		return stateEndValue(s, c) -	} -	return stateBeginString(s, c) -} - -// stateBeginString is the state after reading `{"key": value,`. -func stateBeginString(s *scanner, c byte) int { -	if c <= ' ' && isSpace(c) { -		return scanSkipSpace -	} -	if c == '"' { -		s.step = stateInString -		return scanBeginLiteral -	} -	if isName(c) { -		s.step = stateName -		return scanBeginName -	} -	return s.error(c, "looking for beginning of object key string") -} - -// stateEndValue is the state after completing a value, -// such as after reading `{}` or `true` or `["x"`. -func stateEndValue(s *scanner, c byte) int { -	n := len(s.parseState) -	if n == 0 { -		// Completed top-level before the current byte. -		s.step = stateEndTop -		s.endTop = true -		return stateEndTop(s, c) -	} -	if c <= ' ' && isSpace(c) { -		s.step = stateEndValue -		return scanSkipSpace -	} -	ps := s.parseState[n-1] -	switch ps { -	case parseObjectKey: -		if c == ':' { -			s.parseState[n-1] = parseObjectValue -			s.step = stateBeginValue -			return scanObjectKey -		} -		return s.error(c, "after object key") -	case parseObjectValue: -		if c == ',' { -			s.parseState[n-1] = parseObjectKey -			s.step = stateBeginStringOrEmpty -			return scanObjectValue -		} -		if c == '}' { -			s.popParseState() -			return scanEndObject -		} -		return s.error(c, "after object key:value pair") -	case parseArrayValue: -		if c == ',' { -			s.step = stateBeginValueOrEmpty -			return scanArrayValue -		} -		if c == ']' { -			s.popParseState() -			return scanEndArray -		} -		return s.error(c, "after array element") -	case parseParam: -		if c == ',' { -			s.step = stateBeginValue -			return scanParam -		} -		if c == ')' { -			s.popParseState() -			return scanEndParams -		} -		return s.error(c, "after array element") -	} -	return s.error(c, "") -} - -// stateEndTop is the state after finishing the top-level value, -// such as after reading `{}` or `[1,2,3]`. -// Only space characters should be seen now. -func stateEndTop(s *scanner, c byte) int { -	if c != ' ' && c != '\t' && c != '\r' && c != '\n' { -		// Complain about non-space byte on next call. -		s.error(c, "after top-level value") -	} -	return scanEnd -} - -// stateInString is the state after reading `"`. -func stateInString(s *scanner, c byte) int { -	if c == '"' { -		s.step = stateEndValue -		return scanContinue -	} -	if c == '\\' { -		s.step = stateInStringEsc -		return scanContinue -	} -	if c < 0x20 { -		return s.error(c, "in string literal") -	} -	return scanContinue -} - -// stateInStringEsc is the state after reading `"\` during a quoted string. -func stateInStringEsc(s *scanner, c byte) int { -	switch c { -	case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': -		s.step = stateInString -		return scanContinue -	case 'u': -		s.step = stateInStringEscU -		return scanContinue -	} -	return s.error(c, "in string escape code") -} - -// stateInStringEscU is the state after reading `"\u` during a quoted string. -func stateInStringEscU(s *scanner, c byte) int { -	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { -		s.step = stateInStringEscU1 -		return scanContinue -	} -	// numbers -	return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU1 is the state after reading `"\u1` during a quoted string. -func stateInStringEscU1(s *scanner, c byte) int { -	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { -		s.step = stateInStringEscU12 -		return scanContinue -	} -	// numbers -	return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU12 is the state after reading `"\u12` during a quoted string. -func stateInStringEscU12(s *scanner, c byte) int { -	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { -		s.step = stateInStringEscU123 -		return scanContinue -	} -	// numbers -	return s.error(c, "in \\u hexadecimal character escape") -} - -// stateInStringEscU123 is the state after reading `"\u123` during a quoted string. -func stateInStringEscU123(s *scanner, c byte) int { -	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { -		s.step = stateInString -		return scanContinue -	} -	// numbers -	return s.error(c, "in \\u hexadecimal character escape") -} - -// stateNeg is the state after reading `-` during a number. -func stateNeg(s *scanner, c byte) int { -	if c == '0' { -		s.step = state0 -		return scanContinue -	} -	if '1' <= c && c <= '9' { -		s.step = state1 -		return scanContinue -	} -	return s.error(c, "in numeric literal") -} - -// state1 is the state after reading a non-zero integer during a number, -// such as after reading `1` or `100` but not `0`. -func state1(s *scanner, c byte) int { -	if '0' <= c && c <= '9' { -		s.step = state1 -		return scanContinue -	} -	return state0(s, c) -} - -// state0 is the state after reading `0` during a number. -func state0(s *scanner, c byte) int { -	if c == '.' { -		s.step = stateDot -		return scanContinue -	} -	if c == 'e' || c == 'E' { -		s.step = stateE -		return scanContinue -	} -	return stateEndValue(s, c) -} - -// stateDot is the state after reading the integer and decimal point in a number, -// such as after reading `1.`. -func stateDot(s *scanner, c byte) int { -	if '0' <= c && c <= '9' { -		s.step = stateDot0 -		return scanContinue -	} -	return s.error(c, "after decimal point in numeric literal") -} - -// stateDot0 is the state after reading the integer, decimal point, and subsequent -// digits of a number, such as after reading `3.14`. -func stateDot0(s *scanner, c byte) int { -	if '0' <= c && c <= '9' { -		return scanContinue -	} -	if c == 'e' || c == 'E' { -		s.step = stateE -		return scanContinue -	} -	return stateEndValue(s, c) -} - -// stateE is the state after reading the mantissa and e in a number, -// such as after reading `314e` or `0.314e`. -func stateE(s *scanner, c byte) int { -	if c == '+' || c == '-' { -		s.step = stateESign -		return scanContinue -	} -	return stateESign(s, c) -} - -// stateESign is the state after reading the mantissa, e, and sign in a number, -// such as after reading `314e-` or `0.314e+`. -func stateESign(s *scanner, c byte) int { -	if '0' <= c && c <= '9' { -		s.step = stateE0 -		return scanContinue -	} -	return s.error(c, "in exponent of numeric literal") -} - -// stateE0 is the state after reading the mantissa, e, optional sign, -// and at least one digit of the exponent in a number, -// such as after reading `314e-2` or `0.314e+1` or `3.14e0`. -func stateE0(s *scanner, c byte) int { -	if '0' <= c && c <= '9' { -		return scanContinue -	} -	return stateEndValue(s, c) -} - -// stateNew0 is the state after reading `n`. -func stateNew0(s *scanner, c byte) int { -	if c == 'e' { -		s.step = stateNew1 -		return scanContinue -	} -	s.step = stateName -	return stateName(s, c) -} - -// stateNew1 is the state after reading `ne`. -func stateNew1(s *scanner, c byte) int { -	if c == 'w' { -		s.step = stateNew2 -		return scanContinue -	} -	s.step = stateName -	return stateName(s, c) -} - -// stateNew2 is the state after reading `new`. -func stateNew2(s *scanner, c byte) int { -	s.step = stateName -	if c == ' ' { -		return scanContinue -	} -	return stateName(s, c) -} - -// stateName is the state while reading an unquoted function name. -func stateName(s *scanner, c byte) int { -	if isName(c) { -		return scanContinue -	} -	if c == '(' { -		s.step = stateParamOrEmpty -		s.pushParseState(parseParam) -		return scanParam -	} -	return stateEndValue(s, c) -} - -// stateParamOrEmpty is the state after reading `(`. -func stateParamOrEmpty(s *scanner, c byte) int { -	if c <= ' ' && isSpace(c) { -		return scanSkipSpace -	} -	if c == ')' { -		return stateEndValue(s, c) -	} -	return stateBeginValue(s, c) -} - -// stateT is the state after reading `t`. -func stateT(s *scanner, c byte) int { -	if c == 'r' { -		s.step = stateTr -		return scanContinue -	} -	return s.error(c, "in literal true (expecting 'r')") -} - -// stateTr is the state after reading `tr`. -func stateTr(s *scanner, c byte) int { -	if c == 'u' { -		s.step = stateTru -		return scanContinue -	} -	return s.error(c, "in literal true (expecting 'u')") -} - -// stateTru is the state after reading `tru`. -func stateTru(s *scanner, c byte) int { -	if c == 'e' { -		s.step = stateEndValue -		return scanContinue -	} -	return s.error(c, "in literal true (expecting 'e')") -} - -// stateF is the state after reading `f`. -func stateF(s *scanner, c byte) int { -	if c == 'a' { -		s.step = stateFa -		return scanContinue -	} -	return s.error(c, "in literal false (expecting 'a')") -} - -// stateFa is the state after reading `fa`. -func stateFa(s *scanner, c byte) int { -	if c == 'l' { -		s.step = stateFal -		return scanContinue -	} -	return s.error(c, "in literal false (expecting 'l')") -} - -// stateFal is the state after reading `fal`. -func stateFal(s *scanner, c byte) int { -	if c == 's' { -		s.step = stateFals -		return scanContinue -	} -	return s.error(c, "in literal false (expecting 's')") -} - -// stateFals is the state after reading `fals`. -func stateFals(s *scanner, c byte) int { -	if c == 'e' { -		s.step = stateEndValue -		return scanContinue -	} -	return s.error(c, "in literal false (expecting 'e')") -} - -// stateN is the state after reading `n`. -func stateN(s *scanner, c byte) int { -	if c == 'u' { -		s.step = stateNu -		return scanContinue -	} -	return s.error(c, "in literal null (expecting 'u')") -} - -// stateNu is the state after reading `nu`. -func stateNu(s *scanner, c byte) int { -	if c == 'l' { -		s.step = stateNul -		return scanContinue -	} -	return s.error(c, "in literal null (expecting 'l')") -} - -// stateNul is the state after reading `nul`. -func stateNul(s *scanner, c byte) int { -	if c == 'l' { -		s.step = stateEndValue -		return scanContinue -	} -	return s.error(c, "in literal null (expecting 'l')") -} - -// stateError is the state after reaching a syntax error, -// such as after reading `[1}` or `5.1.2`. -func stateError(s *scanner, c byte) int { -	return scanError -} - -// error records an error and switches to the error state. -func (s *scanner) error(c byte, context string) int { -	s.step = stateError -	s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes} -	return scanError -} - -// quoteChar formats c as a quoted character literal -func quoteChar(c byte) string { -	// special cases - different from quoted strings -	if c == '\'' { -		return `'\''` -	} -	if c == '"' { -		return `'"'` -	} - -	// use quoted string with different quotation marks -	s := strconv.Quote(string(c)) -	return "'" + s[1:len(s)-1] + "'" -} - -// undo causes the scanner to return scanCode from the next state transition. -// This gives callers a simple 1-byte undo mechanism. -func (s *scanner) undo(scanCode int) { -	if s.redo { -		panic("json: invalid use of scanner") -	} -	s.redoCode = scanCode -	s.redoState = s.step -	s.step = stateRedo -	s.redo = true -} - -// stateRedo helps implement the scanner's 1-byte undo. -func stateRedo(s *scanner, c byte) int { -	s.redo = false -	s.step = s.redoState -	return s.redoCode -} diff --git a/vendor/gopkg.in/mgo.v2/internal/json/stream.go b/vendor/gopkg.in/mgo.v2/internal/json/stream.go deleted file mode 100644 index e023702..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/stream.go +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( -	"bytes" -	"errors" -	"io" -) - -// A Decoder reads and decodes JSON values from an input stream. -type Decoder struct { -	r     io.Reader -	buf   []byte -	d     decodeState -	scanp int // start of unread data in buf -	scan  scanner -	err   error - -	tokenState int -	tokenStack []int -} - -// NewDecoder returns a new decoder that reads from r. -// -// The decoder introduces its own buffering and may -// read data from r beyond the JSON values requested. -func NewDecoder(r io.Reader) *Decoder { -	return &Decoder{r: r} -} - -// UseNumber causes the Decoder to unmarshal a number into an interface{} as a -// Number instead of as a float64. -func (dec *Decoder) UseNumber() { dec.d.useNumber = true } - -// Decode reads the next JSON-encoded value from its -// input and stores it in the value pointed to by v. -// -// See the documentation for Unmarshal for details about -// the conversion of JSON into a Go value. -func (dec *Decoder) Decode(v interface{}) error { -	if dec.err != nil { -		return dec.err -	} - -	if err := dec.tokenPrepareForDecode(); err != nil { -		return err -	} - -	if !dec.tokenValueAllowed() { -		return &SyntaxError{msg: "not at beginning of value"} -	} - -	// Read whole value into buffer. -	n, err := dec.readValue() -	if err != nil { -		return err -	} -	dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) -	dec.scanp += n - -	// Don't save err from unmarshal into dec.err: -	// the connection is still usable since we read a complete JSON -	// object from it before the error happened. -	err = dec.d.unmarshal(v) - -	// fixup token streaming state -	dec.tokenValueEnd() - -	return err -} - -// Buffered returns a reader of the data remaining in the Decoder's -// buffer. The reader is valid until the next call to Decode. -func (dec *Decoder) Buffered() io.Reader { -	return bytes.NewReader(dec.buf[dec.scanp:]) -} - -// readValue reads a JSON value into dec.buf. -// It returns the length of the encoding. -func (dec *Decoder) readValue() (int, error) { -	dec.scan.reset() - -	scanp := dec.scanp -	var err error -Input: -	for { -		// Look in the buffer for a new value. -		for i, c := range dec.buf[scanp:] { -			dec.scan.bytes++ -			v := dec.scan.step(&dec.scan, c) -			if v == scanEnd { -				scanp += i -				break Input -			} -			// scanEnd is delayed one byte. -			// We might block trying to get that byte from src, -			// so instead invent a space byte. -			if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd { -				scanp += i + 1 -				break Input -			} -			if v == scanError { -				dec.err = dec.scan.err -				return 0, dec.scan.err -			} -		} -		scanp = len(dec.buf) - -		// Did the last read have an error? -		// Delayed until now to allow buffer scan. -		if err != nil { -			if err == io.EOF { -				if dec.scan.step(&dec.scan, ' ') == scanEnd { -					break Input -				} -				if nonSpace(dec.buf) { -					err = io.ErrUnexpectedEOF -				} -			} -			dec.err = err -			return 0, err -		} - -		n := scanp - dec.scanp -		err = dec.refill() -		scanp = dec.scanp + n -	} -	return scanp - dec.scanp, nil -} - -func (dec *Decoder) refill() error { -	// Make room to read more into the buffer. -	// First slide down data already consumed. -	if dec.scanp > 0 { -		n := copy(dec.buf, dec.buf[dec.scanp:]) -		dec.buf = dec.buf[:n] -		dec.scanp = 0 -	} - -	// Grow buffer if not large enough. -	const minRead = 512 -	if cap(dec.buf)-len(dec.buf) < minRead { -		newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) -		copy(newBuf, dec.buf) -		dec.buf = newBuf -	} - -	// Read. Delay error for next iteration (after scan). -	n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) -	dec.buf = dec.buf[0 : len(dec.buf)+n] - -	return err -} - -func nonSpace(b []byte) bool { -	for _, c := range b { -		if !isSpace(c) { -			return true -		} -	} -	return false -} - -// An Encoder writes JSON values to an output stream. -type Encoder struct { -	w          io.Writer -	err        error -	escapeHTML bool - -	indentBuf    *bytes.Buffer -	indentPrefix string -	indentValue  string - -	ext Extension -} - -// NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { -	return &Encoder{w: w, escapeHTML: true} -} - -// Encode writes the JSON encoding of v to the stream, -// followed by a newline character. -// -// See the documentation for Marshal for details about the -// conversion of Go values to JSON. -func (enc *Encoder) Encode(v interface{}) error { -	if enc.err != nil { -		return enc.err -	} -	e := newEncodeState() -	e.ext = enc.ext -	err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) -	if err != nil { -		return err -	} - -	// Terminate each value with a newline. -	// This makes the output look a little nicer -	// when debugging, and some kind of space -	// is required if the encoded value was a number, -	// so that the reader knows there aren't more -	// digits coming. -	e.WriteByte('\n') - -	b := e.Bytes() -	if enc.indentBuf != nil { -		enc.indentBuf.Reset() -		err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) -		if err != nil { -			return err -		} -		b = enc.indentBuf.Bytes() -	} -	if _, err = enc.w.Write(b); err != nil { -		enc.err = err -	} -	encodeStatePool.Put(e) -	return err -} - -// Indent sets the encoder to format each encoded value with Indent. -func (enc *Encoder) Indent(prefix, indent string) { -	enc.indentBuf = new(bytes.Buffer) -	enc.indentPrefix = prefix -	enc.indentValue = indent -} - -// DisableHTMLEscaping causes the encoder not to escape angle brackets -// ("<" and ">") or ampersands ("&") in JSON strings. -func (enc *Encoder) DisableHTMLEscaping() { -	enc.escapeHTML = false -} - -// RawMessage is a raw encoded JSON value. -// It implements Marshaler and Unmarshaler and can -// be used to delay JSON decoding or precompute a JSON encoding. -type RawMessage []byte - -// MarshalJSON returns *m as the JSON encoding of m. -func (m *RawMessage) MarshalJSON() ([]byte, error) { -	return *m, nil -} - -// UnmarshalJSON sets *m to a copy of data. -func (m *RawMessage) UnmarshalJSON(data []byte) error { -	if m == nil { -		return errors.New("json.RawMessage: UnmarshalJSON on nil pointer") -	} -	*m = append((*m)[0:0], data...) -	return nil -} - -var _ Marshaler = (*RawMessage)(nil) -var _ Unmarshaler = (*RawMessage)(nil) - -// A Token holds a value of one of these types: -// -//	Delim, for the four JSON delimiters [ ] { } -//	bool, for JSON booleans -//	float64, for JSON numbers -//	Number, for JSON numbers -//	string, for JSON string literals -//	nil, for JSON null -// -type Token interface{} - -const ( -	tokenTopValue = iota -	tokenArrayStart -	tokenArrayValue -	tokenArrayComma -	tokenObjectStart -	tokenObjectKey -	tokenObjectColon -	tokenObjectValue -	tokenObjectComma -) - -// advance tokenstate from a separator state to a value state -func (dec *Decoder) tokenPrepareForDecode() error { -	// Note: Not calling peek before switch, to avoid -	// putting peek into the standard Decode path. -	// peek is only called when using the Token API. -	switch dec.tokenState { -	case tokenArrayComma: -		c, err := dec.peek() -		if err != nil { -			return err -		} -		if c != ',' { -			return &SyntaxError{"expected comma after array element", 0} -		} -		dec.scanp++ -		dec.tokenState = tokenArrayValue -	case tokenObjectColon: -		c, err := dec.peek() -		if err != nil { -			return err -		} -		if c != ':' { -			return &SyntaxError{"expected colon after object key", 0} -		} -		dec.scanp++ -		dec.tokenState = tokenObjectValue -	} -	return nil -} - -func (dec *Decoder) tokenValueAllowed() bool { -	switch dec.tokenState { -	case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue: -		return true -	} -	return false -} - -func (dec *Decoder) tokenValueEnd() { -	switch dec.tokenState { -	case tokenArrayStart, tokenArrayValue: -		dec.tokenState = tokenArrayComma -	case tokenObjectValue: -		dec.tokenState = tokenObjectComma -	} -} - -// A Delim is a JSON array or object delimiter, one of [ ] { or }. -type Delim rune - -func (d Delim) String() string { -	return string(d) -} - -// Token returns the next JSON token in the input stream. -// At the end of the input stream, Token returns nil, io.EOF. -// -// Token guarantees that the delimiters [ ] { } it returns are -// properly nested and matched: if Token encounters an unexpected -// delimiter in the input, it will return an error. -// -// The input stream consists of basic JSON values—bool, string, -// number, and null—along with delimiters [ ] { } of type Delim -// to mark the start and end of arrays and objects. -// Commas and colons are elided. -func (dec *Decoder) Token() (Token, error) { -	for { -		c, err := dec.peek() -		if err != nil { -			return nil, err -		} -		switch c { -		case '[': -			if !dec.tokenValueAllowed() { -				return dec.tokenError(c) -			} -			dec.scanp++ -			dec.tokenStack = append(dec.tokenStack, dec.tokenState) -			dec.tokenState = tokenArrayStart -			return Delim('['), nil - -		case ']': -			if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma { -				return dec.tokenError(c) -			} -			dec.scanp++ -			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] -			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] -			dec.tokenValueEnd() -			return Delim(']'), nil - -		case '{': -			if !dec.tokenValueAllowed() { -				return dec.tokenError(c) -			} -			dec.scanp++ -			dec.tokenStack = append(dec.tokenStack, dec.tokenState) -			dec.tokenState = tokenObjectStart -			return Delim('{'), nil - -		case '}': -			if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma { -				return dec.tokenError(c) -			} -			dec.scanp++ -			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] -			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] -			dec.tokenValueEnd() -			return Delim('}'), nil - -		case ':': -			if dec.tokenState != tokenObjectColon { -				return dec.tokenError(c) -			} -			dec.scanp++ -			dec.tokenState = tokenObjectValue -			continue - -		case ',': -			if dec.tokenState == tokenArrayComma { -				dec.scanp++ -				dec.tokenState = tokenArrayValue -				continue -			} -			if dec.tokenState == tokenObjectComma { -				dec.scanp++ -				dec.tokenState = tokenObjectKey -				continue -			} -			return dec.tokenError(c) - -		case '"': -			if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey { -				var x string -				old := dec.tokenState -				dec.tokenState = tokenTopValue -				err := dec.Decode(&x) -				dec.tokenState = old -				if err != nil { -					clearOffset(err) -					return nil, err -				} -				dec.tokenState = tokenObjectColon -				return x, nil -			} -			fallthrough - -		default: -			if !dec.tokenValueAllowed() { -				return dec.tokenError(c) -			} -			var x interface{} -			if err := dec.Decode(&x); err != nil { -				clearOffset(err) -				return nil, err -			} -			return x, nil -		} -	} -} - -func clearOffset(err error) { -	if s, ok := err.(*SyntaxError); ok { -		s.Offset = 0 -	} -} - -func (dec *Decoder) tokenError(c byte) (Token, error) { -	var context string -	switch dec.tokenState { -	case tokenTopValue: -		context = " looking for beginning of value" -	case tokenArrayStart, tokenArrayValue, tokenObjectValue: -		context = " looking for beginning of value" -	case tokenArrayComma: -		context = " after array element" -	case tokenObjectKey: -		context = " looking for beginning of object key string" -	case tokenObjectColon: -		context = " after object key" -	case tokenObjectComma: -		context = " after object key:value pair" -	} -	return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0} -} - -// More reports whether there is another element in the -// current array or object being parsed. -func (dec *Decoder) More() bool { -	c, err := dec.peek() -	return err == nil && c != ']' && c != '}' -} - -func (dec *Decoder) peek() (byte, error) { -	var err error -	for { -		for i := dec.scanp; i < len(dec.buf); i++ { -			c := dec.buf[i] -			if isSpace(c) { -				continue -			} -			dec.scanp = i -			return c, nil -		} -		// buffer has been scanned, now report any error -		if err != nil { -			return 0, err -		} -		err = dec.refill() -	} -} - -/* -TODO - -// EncodeToken writes the given JSON token to the stream. -// It returns an error if the delimiters [ ] { } are not properly used. -// -// EncodeToken does not call Flush, because usually it is part of -// a larger operation such as Encode, and those will call Flush when finished. -// Callers that create an Encoder and then invoke EncodeToken directly, -// without using Encode, need to call Flush when finished to ensure that -// the JSON is written to the underlying writer. -func (e *Encoder) EncodeToken(t Token) error  { -	... -} - -*/ diff --git a/vendor/gopkg.in/mgo.v2/internal/json/tags.go b/vendor/gopkg.in/mgo.v2/internal/json/tags.go deleted file mode 100644 index c38fd51..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/json/tags.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( -	"strings" -) - -// tagOptions is the string following a comma in a struct field's "json" -// tag, or the empty string. It does not include the leading comma. -type tagOptions string - -// parseTag splits a struct field's json tag into its name and -// comma-separated options. -func parseTag(tag string) (string, tagOptions) { -	if idx := strings.Index(tag, ","); idx != -1 { -		return tag[:idx], tagOptions(tag[idx+1:]) -	} -	return tag, tagOptions("") -} - -// Contains reports whether a comma-separated list of options -// contains a particular substr flag. substr must be surrounded by a -// string boundary or commas. -func (o tagOptions) Contains(optionName string) bool { -	if len(o) == 0 { -		return false -	} -	s := string(o) -	for s != "" { -		var next string -		i := strings.Index(s, ",") -		if i >= 0 { -			s, next = s[:i], s[i+1:] -		} -		if s == optionName { -			return true -		} -		s = next -	} -	return false -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c deleted file mode 100644 index 8be0bc4..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c +++ /dev/null @@ -1,77 +0,0 @@ -// +build !windows - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sasl/sasl.h> - -static int mgo_sasl_simple(void *context, int id, const char **result, unsigned int *len) -{ -	if (!result) { -		return SASL_BADPARAM; -	} -	switch (id) { -	case SASL_CB_USER: -		*result = (char *)context; -		break; -	case SASL_CB_AUTHNAME: -		*result = (char *)context; -		break; -	case SASL_CB_LANGUAGE: -		*result = NULL; -		break; -	default: -		return SASL_BADPARAM; -	} -	if (len) { -		*len = *result ? strlen(*result) : 0; -	} -	return SASL_OK; -} - -typedef int (*callback)(void); - -static int mgo_sasl_secret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **result) -{ -	if (!conn || !result || id != SASL_CB_PASS) { -		return SASL_BADPARAM; -	} -	*result = (sasl_secret_t *)context; -	return SASL_OK; -} - -sasl_callback_t *mgo_sasl_callbacks(const char *username, const char *password) -{ -	sasl_callback_t *cb = malloc(4 * sizeof(sasl_callback_t)); -	int n = 0; - -	size_t len = strlen(password); -	sasl_secret_t *secret = (sasl_secret_t*)malloc(sizeof(sasl_secret_t) + len); -	if (!secret) { -		free(cb); -		return NULL; -	} -	strcpy((char *)secret->data, password); -	secret->len = len; - -	cb[n].id = SASL_CB_PASS; -	cb[n].proc = (callback)&mgo_sasl_secret; -	cb[n].context = secret; -	n++; - -	cb[n].id = SASL_CB_USER; -	cb[n].proc = (callback)&mgo_sasl_simple; -	cb[n].context = (char*)username; -	n++; - -	cb[n].id = SASL_CB_AUTHNAME; -	cb[n].proc = (callback)&mgo_sasl_simple; -	cb[n].context = (char*)username; -	n++; - -	cb[n].id = SASL_CB_LIST_END; -	cb[n].proc = NULL; -	cb[n].context = NULL; - -	return cb; -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go deleted file mode 100644 index 8375ddd..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go +++ /dev/null @@ -1,138 +0,0 @@ -// Package sasl is an implementation detail of the mgo package. -// -// This package is not meant to be used by itself. -// - -// +build !windows - -package sasl - -// #cgo LDFLAGS: -lsasl2 -// -// struct sasl_conn {}; -// -// #include <stdlib.h> -// #include <sasl/sasl.h> -// -// sasl_callback_t *mgo_sasl_callbacks(const char *username, const char *password); -// -import "C" - -import ( -	"fmt" -	"strings" -	"sync" -	"unsafe" -) - -type saslStepper interface { -	Step(serverData []byte) (clientData []byte, done bool, err error) -	Close() -} - -type saslSession struct { -	conn *C.sasl_conn_t -	step int -	mech string - -	cstrings  []*C.char -	callbacks *C.sasl_callback_t -} - -var initError error -var initOnce sync.Once - -func initSASL() { -	rc := C.sasl_client_init(nil) -	if rc != C.SASL_OK { -		initError = saslError(rc, nil, "cannot initialize SASL library") -	} -} - -func New(username, password, mechanism, service, host string) (saslStepper, error) { -	initOnce.Do(initSASL) -	if initError != nil { -		return nil, initError -	} - -	ss := &saslSession{mech: mechanism} -	if service == "" { -		service = "mongodb" -	} -	if i := strings.Index(host, ":"); i >= 0 { -		host = host[:i] -	} -	ss.callbacks = C.mgo_sasl_callbacks(ss.cstr(username), ss.cstr(password)) -	rc := C.sasl_client_new(ss.cstr(service), ss.cstr(host), nil, nil, ss.callbacks, 0, &ss.conn) -	if rc != C.SASL_OK { -		ss.Close() -		return nil, saslError(rc, nil, "cannot create new SASL client") -	} -	return ss, nil -} - -func (ss *saslSession) cstr(s string) *C.char { -	cstr := C.CString(s) -	ss.cstrings = append(ss.cstrings, cstr) -	return cstr -} - -func (ss *saslSession) Close() { -	for _, cstr := range ss.cstrings { -		C.free(unsafe.Pointer(cstr)) -	} -	ss.cstrings = nil - -	if ss.callbacks != nil { -		C.free(unsafe.Pointer(ss.callbacks)) -	} - -	// The documentation of SASL dispose makes it clear that this should only -	// be done when the connection is done, not when the authentication phase -	// is done, because an encryption layer may have been negotiated. -	// Even then, we'll do this for now, because it's simpler and prevents -	// keeping track of this state for every socket. If it breaks, we'll fix it. -	C.sasl_dispose(&ss.conn) -} - -func (ss *saslSession) Step(serverData []byte) (clientData []byte, done bool, err error) { -	ss.step++ -	if ss.step > 10 { -		return nil, false, fmt.Errorf("too many SASL steps without authentication") -	} -	var cclientData *C.char -	var cclientDataLen C.uint -	var rc C.int -	if ss.step == 1 { -		var mechanism *C.char // ignored - must match cred -		rc = C.sasl_client_start(ss.conn, ss.cstr(ss.mech), nil, &cclientData, &cclientDataLen, &mechanism) -	} else { -		var cserverData *C.char -		var cserverDataLen C.uint -		if len(serverData) > 0 { -			cserverData = (*C.char)(unsafe.Pointer(&serverData[0])) -			cserverDataLen = C.uint(len(serverData)) -		} -		rc = C.sasl_client_step(ss.conn, cserverData, cserverDataLen, nil, &cclientData, &cclientDataLen) -	} -	if cclientData != nil && cclientDataLen > 0 { -		clientData = C.GoBytes(unsafe.Pointer(cclientData), C.int(cclientDataLen)) -	} -	if rc == C.SASL_OK { -		return clientData, true, nil -	} -	if rc == C.SASL_CONTINUE { -		return clientData, false, nil -	} -	return nil, false, saslError(rc, ss.conn, "cannot establish SASL session") -} - -func saslError(rc C.int, conn *C.sasl_conn_t, msg string) error { -	var detail string -	if conn == nil { -		detail = C.GoString(C.sasl_errstring(rc, nil, nil)) -	} else { -		detail = C.GoString(C.sasl_errdetail(conn)) -	} -	return fmt.Errorf(msg + ": " + detail) -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c deleted file mode 100644 index c359fd6..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "sasl_windows.h" - -static const LPSTR SSPI_PACKAGE_NAME = "kerberos"; - -SECURITY_STATUS SEC_ENTRY sspi_acquire_credentials_handle(CredHandle *cred_handle, char *username, char *password, char *domain) -{ -	SEC_WINNT_AUTH_IDENTITY auth_identity; -	SECURITY_INTEGER ignored; - -	auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; -	auth_identity.User = (LPSTR) username; -	auth_identity.UserLength = strlen(username); -	auth_identity.Password = NULL; -	auth_identity.PasswordLength = 0; -	if(password){ -		auth_identity.Password = (LPSTR) password; -		auth_identity.PasswordLength = strlen(password); -	} -	auth_identity.Domain = (LPSTR) domain; -	auth_identity.DomainLength = strlen(domain); -	return call_sspi_acquire_credentials_handle(NULL, SSPI_PACKAGE_NAME, SECPKG_CRED_OUTBOUND, NULL, &auth_identity, NULL, NULL, cred_handle, &ignored); -} - -int sspi_step(CredHandle *cred_handle, int has_context, CtxtHandle *context, PVOID buffer, ULONG buffer_length, PVOID *out_buffer, ULONG *out_buffer_length,  char *target) -{ -	SecBufferDesc inbuf; -	SecBuffer in_bufs[1]; -	SecBufferDesc outbuf; -	SecBuffer out_bufs[1]; - -	if (has_context > 0) { -		// If we already have a context, we now have data to send. -		// Put this data in an inbuf. -		inbuf.ulVersion = SECBUFFER_VERSION; -		inbuf.cBuffers = 1; -		inbuf.pBuffers = in_bufs; -		in_bufs[0].pvBuffer = buffer; -		in_bufs[0].cbBuffer = buffer_length; -		in_bufs[0].BufferType = SECBUFFER_TOKEN; -	} - -	outbuf.ulVersion = SECBUFFER_VERSION; -	outbuf.cBuffers = 1; -	outbuf.pBuffers = out_bufs; -	out_bufs[0].pvBuffer = NULL; -	out_bufs[0].cbBuffer = 0; -	out_bufs[0].BufferType = SECBUFFER_TOKEN; - -	ULONG context_attr = 0; - -	int ret = call_sspi_initialize_security_context(cred_handle, -	          has_context > 0 ? context : NULL, -	          (LPSTR) target, -	          ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH, -	          0, -	          SECURITY_NETWORK_DREP, -	          has_context > 0 ? &inbuf : NULL, -	          0, -	          context, -	          &outbuf, -	          &context_attr, -	          NULL); - -	*out_buffer = malloc(out_bufs[0].cbBuffer); -	*out_buffer_length = out_bufs[0].cbBuffer; -	memcpy(*out_buffer, out_bufs[0].pvBuffer, *out_buffer_length); - -	return ret; -} - -int sspi_send_client_authz_id(CtxtHandle *context, PVOID *buffer, ULONG *buffer_length, char *user_plus_realm) -{ -	SecPkgContext_Sizes sizes; -	SECURITY_STATUS status = call_sspi_query_context_attributes(context, SECPKG_ATTR_SIZES, &sizes); - -	if (status != SEC_E_OK) { -		return status; -	} - -	size_t user_plus_realm_length = strlen(user_plus_realm); -	int msgSize = 4 + user_plus_realm_length; -	char *msg = malloc((sizes.cbSecurityTrailer + msgSize + sizes.cbBlockSize) * sizeof(char)); -	msg[sizes.cbSecurityTrailer + 0] = 1; -	msg[sizes.cbSecurityTrailer + 1] = 0; -	msg[sizes.cbSecurityTrailer + 2] = 0; -	msg[sizes.cbSecurityTrailer + 3] = 0; -	memcpy(&msg[sizes.cbSecurityTrailer + 4], user_plus_realm, user_plus_realm_length); - -	SecBuffer wrapBufs[3]; -	SecBufferDesc wrapBufDesc; -	wrapBufDesc.cBuffers = 3; -	wrapBufDesc.pBuffers = wrapBufs; -	wrapBufDesc.ulVersion = SECBUFFER_VERSION; - -	wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; -	wrapBufs[0].BufferType = SECBUFFER_TOKEN; -	wrapBufs[0].pvBuffer = msg; - -	wrapBufs[1].cbBuffer = msgSize; -	wrapBufs[1].BufferType = SECBUFFER_DATA; -	wrapBufs[1].pvBuffer = msg + sizes.cbSecurityTrailer; - -	wrapBufs[2].cbBuffer = sizes.cbBlockSize; -	wrapBufs[2].BufferType = SECBUFFER_PADDING; -	wrapBufs[2].pvBuffer = msg + sizes.cbSecurityTrailer + msgSize; - -	status = call_sspi_encrypt_message(context, SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); -	if (status != SEC_E_OK) { -		free(msg); -		return status; -	} - -	*buffer_length = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; -	*buffer = malloc(*buffer_length); - -	memcpy(*buffer, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); -	memcpy(*buffer + wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); -	memcpy(*buffer + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); - -	free(msg); -	return SEC_E_OK; -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go deleted file mode 100644 index d8ec001..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go +++ /dev/null @@ -1,142 +0,0 @@ -package sasl - -// #include "sasl_windows.h" -import "C" - -import ( -	"fmt" -	"strings" -	"sync" -	"unsafe" -) - -type saslStepper interface { -	Step(serverData []byte) (clientData []byte, done bool, err error) -	Close() -} - -type saslSession struct { -	// Credentials -	mech          string -	service       string -	host          string -	userPlusRealm string -	target        string -	domain        string - -	// Internal state -	authComplete bool -	errored      bool -	step         int - -	// C internal state -	credHandle C.CredHandle -	context    C.CtxtHandle -	hasContext C.int - -	// Keep track of pointers we need to explicitly free -	stringsToFree []*C.char -} - -var initError error -var initOnce sync.Once - -func initSSPI() { -	rc := C.load_secur32_dll() -	if rc != 0 { -		initError = fmt.Errorf("Error loading libraries: %v", rc) -	} -} - -func New(username, password, mechanism, service, host string) (saslStepper, error) { -	initOnce.Do(initSSPI) -	ss := &saslSession{mech: mechanism, hasContext: 0, userPlusRealm: username} -	if service == "" { -		service = "mongodb" -	} -	if i := strings.Index(host, ":"); i >= 0 { -		host = host[:i] -	} -	ss.service = service -	ss.host = host - -	usernameComponents := strings.Split(username, "@") -	if len(usernameComponents) < 2 { -		return nil, fmt.Errorf("Username '%v' doesn't contain a realm!", username) -	} -	user := usernameComponents[0] -	ss.domain = usernameComponents[1] -	ss.target = fmt.Sprintf("%s/%s", ss.service, ss.host) - -	var status C.SECURITY_STATUS -	// Step 0: call AcquireCredentialsHandle to get a nice SSPI CredHandle -	if len(password) > 0 { -		status = C.sspi_acquire_credentials_handle(&ss.credHandle, ss.cstr(user), ss.cstr(password), ss.cstr(ss.domain)) -	} else { -		status = C.sspi_acquire_credentials_handle(&ss.credHandle, ss.cstr(user), nil, ss.cstr(ss.domain)) -	} -	if status != C.SEC_E_OK { -		ss.errored = true -		return nil, fmt.Errorf("Couldn't create new SSPI client, error code %v", status) -	} -	return ss, nil -} - -func (ss *saslSession) cstr(s string) *C.char { -	cstr := C.CString(s) -	ss.stringsToFree = append(ss.stringsToFree, cstr) -	return cstr -} - -func (ss *saslSession) Close() { -	for _, cstr := range ss.stringsToFree { -		C.free(unsafe.Pointer(cstr)) -	} -} - -func (ss *saslSession) Step(serverData []byte) (clientData []byte, done bool, err error) { -	ss.step++ -	if ss.step > 10 { -		return nil, false, fmt.Errorf("too many SSPI steps without authentication") -	} -	var buffer C.PVOID -	var bufferLength C.ULONG -	var outBuffer C.PVOID -	var outBufferLength C.ULONG -	if len(serverData) > 0 { -		buffer = (C.PVOID)(unsafe.Pointer(&serverData[0])) -		bufferLength = C.ULONG(len(serverData)) -	} -	var status C.int -	if ss.authComplete { -		// Step 3: last bit of magic to use the correct server credentials -		status = C.sspi_send_client_authz_id(&ss.context, &outBuffer, &outBufferLength, ss.cstr(ss.userPlusRealm)) -	} else { -		// Step 1 + Step 2: set up security context with the server and TGT -		status = C.sspi_step(&ss.credHandle, ss.hasContext, &ss.context, buffer, bufferLength, &outBuffer, &outBufferLength, ss.cstr(ss.target)) -	} -	if outBuffer != C.PVOID(nil) { -		defer C.free(unsafe.Pointer(outBuffer)) -	} -	if status != C.SEC_E_OK && status != C.SEC_I_CONTINUE_NEEDED { -		ss.errored = true -		return nil, false, ss.handleSSPIErrorCode(status) -	} - -	clientData = C.GoBytes(unsafe.Pointer(outBuffer), C.int(outBufferLength)) -	if status == C.SEC_E_OK { -		ss.authComplete = true -		return clientData, true, nil -	} else { -		ss.hasContext = 1 -		return clientData, false, nil -	} -} - -func (ss *saslSession) handleSSPIErrorCode(code C.int) error { -	switch { -	case code == C.SEC_E_TARGET_UNKNOWN: -		return fmt.Errorf("Target %v@%v not found", ss.target, ss.domain) -	} -	return fmt.Errorf("Unknown error doing step %v, error code %v", ss.step, code) -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h deleted file mode 100644 index a6b0395..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h +++ /dev/null @@ -1,7 +0,0 @@ -#include <windows.h> - -#include "sspi_windows.h" - -SECURITY_STATUS SEC_ENTRY sspi_acquire_credentials_handle(CredHandle* cred_handle, char* username, char* password, char* domain); -int sspi_step(CredHandle* cred_handle, int has_context, CtxtHandle* context, PVOID buffer, ULONG buffer_length, PVOID* out_buffer, ULONG* out_buffer_length, char* target); -int sspi_send_client_authz_id(CtxtHandle* context, PVOID* buffer, ULONG* buffer_length, char* user_plus_realm); diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c deleted file mode 100644 index 63f9a6f..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c +++ /dev/null @@ -1,96 +0,0 @@ -// Code adapted from the NodeJS kerberos library: -//  -//   https://github.com/christkv/kerberos/tree/master/lib/win32/kerberos_sspi.c -// -// Under the terms of the Apache License, Version 2.0: -// -//   http://www.apache.org/licenses/LICENSE-2.0 -// -#include <stdlib.h> - -#include "sspi_windows.h" - -static HINSTANCE sspi_secur32_dll = NULL; - -int load_secur32_dll() -{ -	sspi_secur32_dll = LoadLibrary("secur32.dll"); -	if (sspi_secur32_dll == NULL) { -		return GetLastError(); -	} -	return 0; -} - -SECURITY_STATUS SEC_ENTRY call_sspi_encrypt_message(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo) -{ -	if (sspi_secur32_dll == NULL) { -		return -1; -	} -	encryptMessage_fn pfn_encryptMessage = (encryptMessage_fn) GetProcAddress(sspi_secur32_dll, "EncryptMessage"); -	if (!pfn_encryptMessage) { -		return -2; -	} -	return (*pfn_encryptMessage)(phContext, fQOP, pMessage, MessageSeqNo); -} - -SECURITY_STATUS SEC_ENTRY call_sspi_acquire_credentials_handle( -	LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, -        void *pvLogonId, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, -        PCredHandle phCredential, PTimeStamp ptsExpiry) -{ -	if (sspi_secur32_dll == NULL) { -		return -1; -	} -	acquireCredentialsHandle_fn pfn_acquireCredentialsHandle; -#ifdef _UNICODE -	pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn) GetProcAddress(sspi_secur32_dll, "AcquireCredentialsHandleW"); -#else -	pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn) GetProcAddress(sspi_secur32_dll, "AcquireCredentialsHandleA"); -#endif -	if (!pfn_acquireCredentialsHandle) { -		return -2; -	} -	return (*pfn_acquireCredentialsHandle)( -		pszPrincipal, pszPackage, fCredentialUse, pvLogonId, pAuthData, -	        pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry); -} - -SECURITY_STATUS SEC_ENTRY call_sspi_initialize_security_context( -	PCredHandle phCredential, PCtxtHandle phContext, LPSTR pszTargetName, -	unsigned long fContextReq, unsigned long Reserved1, unsigned long TargetDataRep, -	PSecBufferDesc pInput, unsigned long Reserved2, PCtxtHandle phNewContext, -	PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry) -{ -	if (sspi_secur32_dll == NULL) { -		return -1; -	} -	initializeSecurityContext_fn pfn_initializeSecurityContext; -#ifdef _UNICODE -	pfn_initializeSecurityContext = (initializeSecurityContext_fn) GetProcAddress(sspi_secur32_dll, "InitializeSecurityContextW"); -#else -	pfn_initializeSecurityContext = (initializeSecurityContext_fn) GetProcAddress(sspi_secur32_dll, "InitializeSecurityContextA"); -#endif -	if (!pfn_initializeSecurityContext) { -		return -2; -	} -	return (*pfn_initializeSecurityContext)( -		phCredential, phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep, -		pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry); -} - -SECURITY_STATUS SEC_ENTRY call_sspi_query_context_attributes(PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer) -{ -	if (sspi_secur32_dll == NULL) { -		return -1; -	} -	queryContextAttributes_fn pfn_queryContextAttributes; -#ifdef _UNICODE -	pfn_queryContextAttributes = (queryContextAttributes_fn) GetProcAddress(sspi_secur32_dll, "QueryContextAttributesW"); -#else -	pfn_queryContextAttributes = (queryContextAttributes_fn) GetProcAddress(sspi_secur32_dll, "QueryContextAttributesA"); -#endif -	if (!pfn_queryContextAttributes) { -		return -2; -	} -	return (*pfn_queryContextAttributes)(phContext, ulAttribute, pBuffer); -} diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h deleted file mode 100644 index d283270..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h +++ /dev/null @@ -1,70 +0,0 @@ -// Code adapted from the NodeJS kerberos library: -//  -//   https://github.com/christkv/kerberos/tree/master/lib/win32/kerberos_sspi.h -// -// Under the terms of the Apache License, Version 2.0: -// -//   http://www.apache.org/licenses/LICENSE-2.0 -// -#ifndef SSPI_WINDOWS_H -#define SSPI_WINDOWS_H - -#define SECURITY_WIN32 1 - -#include <windows.h> -#include <sspi.h> - -int load_secur32_dll(); - -SECURITY_STATUS SEC_ENTRY call_sspi_encrypt_message(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo); - -typedef DWORD (WINAPI *encryptMessage_fn)(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo); - -SECURITY_STATUS SEC_ENTRY call_sspi_acquire_credentials_handle( -    LPSTR pszPrincipal,             // Name of principal -    LPSTR pszPackage,               // Name of package -    unsigned long fCredentialUse,   // Flags indicating use -    void *pvLogonId,                // Pointer to logon ID -    void *pAuthData,                // Package specific data -    SEC_GET_KEY_FN pGetKeyFn,       // Pointer to GetKey() func -    void *pvGetKeyArgument,         // Value to pass to GetKey() -    PCredHandle phCredential,       // (out) Cred Handle -    PTimeStamp ptsExpiry            // (out) Lifetime (optional) -); - -typedef DWORD (WINAPI *acquireCredentialsHandle_fn)( -    LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse, -    void *pvLogonId, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, -    PCredHandle phCredential, PTimeStamp ptsExpiry -); - -SECURITY_STATUS SEC_ENTRY call_sspi_initialize_security_context( -    PCredHandle phCredential,       // Cred to base context -    PCtxtHandle phContext,          // Existing context (OPT) -    LPSTR pszTargetName,            // Name of target -    unsigned long fContextReq,      // Context Requirements -    unsigned long Reserved1,        // Reserved, MBZ -    unsigned long TargetDataRep,    // Data rep of target -    PSecBufferDesc pInput,          // Input Buffers -    unsigned long Reserved2,        // Reserved, MBZ -    PCtxtHandle phNewContext,       // (out) New Context handle -    PSecBufferDesc pOutput,         // (inout) Output Buffers -    unsigned long *pfContextAttr,   // (out) Context attrs -    PTimeStamp ptsExpiry            // (out) Life span (OPT) -); - -typedef DWORD (WINAPI *initializeSecurityContext_fn)( -    PCredHandle phCredential, PCtxtHandle phContext, LPSTR pszTargetName, unsigned long fContextReq, -    unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2, -    PCtxtHandle phNewContext, PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry); - -SECURITY_STATUS SEC_ENTRY call_sspi_query_context_attributes( -    PCtxtHandle phContext,          // Context to query -    unsigned long ulAttribute,      // Attribute to query -    void *pBuffer                   // Buffer for attributes -); - -typedef DWORD (WINAPI *queryContextAttributes_fn)( -    PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer); - -#endif // SSPI_WINDOWS_H diff --git a/vendor/gopkg.in/mgo.v2/internal/scram/scram.go b/vendor/gopkg.in/mgo.v2/internal/scram/scram.go deleted file mode 100644 index 80cda91..0000000 --- a/vendor/gopkg.in/mgo.v2/internal/scram/scram.go +++ /dev/null @@ -1,266 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2014 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Pacakage scram implements a SCRAM-{SHA-1,etc} client per RFC5802. -// -// http://tools.ietf.org/html/rfc5802 -// -package scram - -import ( -	"bytes" -	"crypto/hmac" -	"crypto/rand" -	"encoding/base64" -	"fmt" -	"hash" -	"strconv" -	"strings" -) - -// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc). -// -// A Client may be used within a SASL conversation with logic resembling: -// -//    var in []byte -//    var client = scram.NewClient(sha1.New, user, pass) -//    for client.Step(in) { -//            out := client.Out() -//            // send out to server -//            in := serverOut -//    } -//    if client.Err() != nil { -//            // auth failed -//    } -// -type Client struct { -	newHash func() hash.Hash - -	user string -	pass string -	step int -	out  bytes.Buffer -	err  error - -	clientNonce []byte -	serverNonce []byte -	saltedPass  []byte -	authMsg     bytes.Buffer -} - -// NewClient returns a new SCRAM-* client with the provided hash algorithm. -// -// For SCRAM-SHA-1, for example, use: -// -//    client := scram.NewClient(sha1.New, user, pass) -// -func NewClient(newHash func() hash.Hash, user, pass string) *Client { -	c := &Client{ -		newHash: newHash, -		user:    user, -		pass:    pass, -	} -	c.out.Grow(256) -	c.authMsg.Grow(256) -	return c -} - -// Out returns the data to be sent to the server in the current step. -func (c *Client) Out() []byte { -	if c.out.Len() == 0 { -		return nil -	} -	return c.out.Bytes() -} - -// Err returns the error that ocurred, or nil if there were no errors. -func (c *Client) Err() error { -	return c.err -} - -// SetNonce sets the client nonce to the provided value. -// If not set, the nonce is generated automatically out of crypto/rand on the first step. -func (c *Client) SetNonce(nonce []byte) { -	c.clientNonce = nonce -} - -var escaper = strings.NewReplacer("=", "=3D", ",", "=2C") - -// Step processes the incoming data from the server and makes the -// next round of data for the server available via Client.Out. -// Step returns false if there are no errors and more data is -// still expected. -func (c *Client) Step(in []byte) bool { -	c.out.Reset() -	if c.step > 2 || c.err != nil { -		return false -	} -	c.step++ -	switch c.step { -	case 1: -		c.err = c.step1(in) -	case 2: -		c.err = c.step2(in) -	case 3: -		c.err = c.step3(in) -	} -	return c.step > 2 || c.err != nil -} - -func (c *Client) step1(in []byte) error { -	if len(c.clientNonce) == 0 { -		const nonceLen = 6 -		buf := make([]byte, nonceLen + b64.EncodedLen(nonceLen)) -		if _, err := rand.Read(buf[:nonceLen]); err != nil { -			return fmt.Errorf("cannot read random SCRAM-SHA-1 nonce from operating system: %v", err) -		} -		c.clientNonce = buf[nonceLen:] -		b64.Encode(c.clientNonce, buf[:nonceLen]) -	} -	c.authMsg.WriteString("n=") -	escaper.WriteString(&c.authMsg, c.user) -	c.authMsg.WriteString(",r=") -	c.authMsg.Write(c.clientNonce) - -	c.out.WriteString("n,,") -	c.out.Write(c.authMsg.Bytes()) -	return nil -} - -var b64 = base64.StdEncoding - -func (c *Client) step2(in []byte) error { -	c.authMsg.WriteByte(',') -	c.authMsg.Write(in) - -	fields := bytes.Split(in, []byte(",")) -	if len(fields) != 3 { -		return fmt.Errorf("expected 3 fields in first SCRAM-SHA-1 server message, got %d: %q", len(fields), in) -	} -	if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 { -		return fmt.Errorf("server sent an invalid SCRAM-SHA-1 nonce: %q", fields[0]) -	} -	if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 { -		return fmt.Errorf("server sent an invalid SCRAM-SHA-1 salt: %q", fields[1]) -	} -	if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 { -		return fmt.Errorf("server sent an invalid SCRAM-SHA-1 iteration count: %q", fields[2]) -	} - -	c.serverNonce = fields[0][2:] -	if !bytes.HasPrefix(c.serverNonce, c.clientNonce) { -		return fmt.Errorf("server SCRAM-SHA-1 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce) -	} - -	salt := make([]byte, b64.DecodedLen(len(fields[1][2:]))) -	n, err := b64.Decode(salt, fields[1][2:]) -	if err != nil { -		return fmt.Errorf("cannot decode SCRAM-SHA-1 salt sent by server: %q", fields[1]) -	} -	salt = salt[:n] -	iterCount, err := strconv.Atoi(string(fields[2][2:])) -	if err != nil { -		return fmt.Errorf("server sent an invalid SCRAM-SHA-1 iteration count: %q", fields[2]) -	} -	c.saltPassword(salt, iterCount) - -	c.authMsg.WriteString(",c=biws,r=") -	c.authMsg.Write(c.serverNonce) - -	c.out.WriteString("c=biws,r=") -	c.out.Write(c.serverNonce) -	c.out.WriteString(",p=") -	c.out.Write(c.clientProof()) -	return nil -} - -func (c *Client) step3(in []byte) error { -	var isv, ise bool -	var fields = bytes.Split(in, []byte(",")) -	if len(fields) == 1 { -		isv = bytes.HasPrefix(fields[0], []byte("v=")) -		ise = bytes.HasPrefix(fields[0], []byte("e=")) -	} -	if ise { -		return fmt.Errorf("SCRAM-SHA-1 authentication error: %s", fields[0][2:]) -	} else if !isv { -		return fmt.Errorf("unsupported SCRAM-SHA-1 final message from server: %q", in) -	} -	if !bytes.Equal(c.serverSignature(), fields[0][2:]) { -		return fmt.Errorf("cannot authenticate SCRAM-SHA-1 server signature: %q", fields[0][2:]) -	} -	return nil -} - -func (c *Client) saltPassword(salt []byte, iterCount int) { -	mac := hmac.New(c.newHash, []byte(c.pass)) -	mac.Write(salt) -	mac.Write([]byte{0, 0, 0, 1}) -	ui := mac.Sum(nil) -	hi := make([]byte, len(ui)) -	copy(hi, ui) -	for i := 1; i < iterCount; i++ { -		mac.Reset() -		mac.Write(ui) -		mac.Sum(ui[:0]) -		for j, b := range ui { -			hi[j] ^= b -		} -	} -	c.saltedPass = hi -} - -func (c *Client) clientProof() []byte { -	mac := hmac.New(c.newHash, c.saltedPass) -	mac.Write([]byte("Client Key")) -	clientKey := mac.Sum(nil) -	hash := c.newHash() -	hash.Write(clientKey) -	storedKey := hash.Sum(nil) -	mac = hmac.New(c.newHash, storedKey) -	mac.Write(c.authMsg.Bytes()) -	clientProof := mac.Sum(nil) -	for i, b := range clientKey { -		clientProof[i] ^= b -	} -	clientProof64 := make([]byte, b64.EncodedLen(len(clientProof))) -	b64.Encode(clientProof64, clientProof) -	return clientProof64 -} - -func (c *Client) serverSignature() []byte { -	mac := hmac.New(c.newHash, c.saltedPass) -	mac.Write([]byte("Server Key")) -	serverKey := mac.Sum(nil) - -	mac = hmac.New(c.newHash, serverKey) -	mac.Write(c.authMsg.Bytes()) -	serverSignature := mac.Sum(nil) - -	encoded := make([]byte, b64.EncodedLen(len(serverSignature))) -	b64.Encode(encoded, serverSignature) -	return encoded -} diff --git a/vendor/gopkg.in/mgo.v2/log.go b/vendor/gopkg.in/mgo.v2/log.go deleted file mode 100644 index 53eb423..0000000 --- a/vendor/gopkg.in/mgo.v2/log.go +++ /dev/null @@ -1,133 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"fmt" -	"sync" -) - -// --------------------------------------------------------------------------- -// Logging integration. - -// Avoid importing the log type information unnecessarily.  There's a small cost -// associated with using an interface rather than the type.  Depending on how -// often the logger is plugged in, it would be worth using the type instead. -type log_Logger interface { -	Output(calldepth int, s string) error -} - -var ( -	globalLogger log_Logger -	globalDebug  bool -	globalMutex  sync.Mutex -) - -// RACE WARNING: There are known data races when logging, which are manually -// silenced when the race detector is in use. These data races won't be -// observed in typical use, because logging is supposed to be set up once when -// the application starts. Having raceDetector as a constant, the compiler -// should elide the locks altogether in actual use. - -// Specify the *log.Logger object where log messages should be sent to. -func SetLogger(logger log_Logger) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	globalLogger = logger -} - -// Enable the delivery of debug messages to the logger.  Only meaningful -// if a logger is also set. -func SetDebug(debug bool) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	globalDebug = debug -} - -func log(v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalLogger != nil { -		globalLogger.Output(2, fmt.Sprint(v...)) -	} -} - -func logln(v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalLogger != nil { -		globalLogger.Output(2, fmt.Sprintln(v...)) -	} -} - -func logf(format string, v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalLogger != nil { -		globalLogger.Output(2, fmt.Sprintf(format, v...)) -	} -} - -func debug(v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalDebug && globalLogger != nil { -		globalLogger.Output(2, fmt.Sprint(v...)) -	} -} - -func debugln(v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalDebug && globalLogger != nil { -		globalLogger.Output(2, fmt.Sprintln(v...)) -	} -} - -func debugf(format string, v ...interface{}) { -	if raceDetector { -		globalMutex.Lock() -		defer globalMutex.Unlock() -	} -	if globalDebug && globalLogger != nil { -		globalLogger.Output(2, fmt.Sprintf(format, v...)) -	} -} diff --git a/vendor/gopkg.in/mgo.v2/queue.go b/vendor/gopkg.in/mgo.v2/queue.go deleted file mode 100644 index e9245de..0000000 --- a/vendor/gopkg.in/mgo.v2/queue.go +++ /dev/null @@ -1,91 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -type queue struct { -	elems               []interface{} -	nelems, popi, pushi int -} - -func (q *queue) Len() int { -	return q.nelems -} - -func (q *queue) Push(elem interface{}) { -	//debugf("Pushing(pushi=%d popi=%d cap=%d): %#v\n", -	//       q.pushi, q.popi, len(q.elems), elem) -	if q.nelems == len(q.elems) { -		q.expand() -	} -	q.elems[q.pushi] = elem -	q.nelems++ -	q.pushi = (q.pushi + 1) % len(q.elems) -	//debugf(" Pushed(pushi=%d popi=%d cap=%d): %#v\n", -	//       q.pushi, q.popi, len(q.elems), elem) -} - -func (q *queue) Pop() (elem interface{}) { -	//debugf("Popping(pushi=%d popi=%d cap=%d)\n", -	//       q.pushi, q.popi, len(q.elems)) -	if q.nelems == 0 { -		return nil -	} -	elem = q.elems[q.popi] -	q.elems[q.popi] = nil // Help GC. -	q.nelems-- -	q.popi = (q.popi + 1) % len(q.elems) -	//debugf(" Popped(pushi=%d popi=%d cap=%d): %#v\n", -	//       q.pushi, q.popi, len(q.elems), elem) -	return elem -} - -func (q *queue) expand() { -	curcap := len(q.elems) -	var newcap int -	if curcap == 0 { -		newcap = 8 -	} else if curcap < 1024 { -		newcap = curcap * 2 -	} else { -		newcap = curcap + (curcap / 4) -	} -	elems := make([]interface{}, newcap) - -	if q.popi == 0 { -		copy(elems, q.elems) -		q.pushi = curcap -	} else { -		newpopi := newcap - (curcap - q.popi) -		copy(elems, q.elems[:q.popi]) -		copy(elems[newpopi:], q.elems[q.popi:]) -		q.popi = newpopi -	} -	for i := range q.elems { -		q.elems[i] = nil // Help GC. -	} -	q.elems = elems -} diff --git a/vendor/gopkg.in/mgo.v2/raceoff.go b/vendor/gopkg.in/mgo.v2/raceoff.go deleted file mode 100644 index e60b141..0000000 --- a/vendor/gopkg.in/mgo.v2/raceoff.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build !race - -package mgo - -const raceDetector = false diff --git a/vendor/gopkg.in/mgo.v2/raceon.go b/vendor/gopkg.in/mgo.v2/raceon.go deleted file mode 100644 index 737b08e..0000000 --- a/vendor/gopkg.in/mgo.v2/raceon.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build race - -package mgo - -const raceDetector = true diff --git a/vendor/gopkg.in/mgo.v2/saslimpl.go b/vendor/gopkg.in/mgo.v2/saslimpl.go deleted file mode 100644 index 0d25f25..0000000 --- a/vendor/gopkg.in/mgo.v2/saslimpl.go +++ /dev/null @@ -1,11 +0,0 @@ -//+build sasl - -package mgo - -import ( -	"gopkg.in/mgo.v2/internal/sasl" -) - -func saslNew(cred Credential, host string) (saslStepper, error) { -	return sasl.New(cred.Username, cred.Password, cred.Mechanism, cred.Service, host) -} diff --git a/vendor/gopkg.in/mgo.v2/saslstub.go b/vendor/gopkg.in/mgo.v2/saslstub.go deleted file mode 100644 index 6e9e309..0000000 --- a/vendor/gopkg.in/mgo.v2/saslstub.go +++ /dev/null @@ -1,11 +0,0 @@ -//+build !sasl - -package mgo - -import ( -	"fmt" -) - -func saslNew(cred Credential, host string) (saslStepper, error) { -	return nil, fmt.Errorf("SASL support not enabled during build (-tags sasl)") -} diff --git a/vendor/gopkg.in/mgo.v2/server.go b/vendor/gopkg.in/mgo.v2/server.go deleted file mode 100644 index 3925986..0000000 --- a/vendor/gopkg.in/mgo.v2/server.go +++ /dev/null @@ -1,463 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"errors" -	"net" -	"sort" -	"sync" -	"time" - -	"gopkg.in/mgo.v2/bson" -) - -// --------------------------------------------------------------------------- -// Mongo server encapsulation. - -type mongoServer struct { -	sync.RWMutex -	Addr          string -	ResolvedAddr  string -	tcpaddr       *net.TCPAddr -	unusedSockets []*mongoSocket -	liveSockets   []*mongoSocket -	closed        bool -	abended       bool -	sync          chan bool -	dial          dialer -	pingValue     time.Duration -	pingIndex     int -	pingCount     uint32 -	pingWindow    [6]time.Duration -	info          *mongoServerInfo -} - -type dialer struct { -	old func(addr net.Addr) (net.Conn, error) -	new func(addr *ServerAddr) (net.Conn, error) -} - -func (dial dialer) isSet() bool { -	return dial.old != nil || dial.new != nil -} - -type mongoServerInfo struct { -	Master         bool -	Mongos         bool -	Tags           bson.D -	MaxWireVersion int -	SetName        string -} - -var defaultServerInfo mongoServerInfo - -func newServer(addr string, tcpaddr *net.TCPAddr, sync chan bool, dial dialer) *mongoServer { -	server := &mongoServer{ -		Addr:         addr, -		ResolvedAddr: tcpaddr.String(), -		tcpaddr:      tcpaddr, -		sync:         sync, -		dial:         dial, -		info:         &defaultServerInfo, -		pingValue:    time.Hour, // Push it back before an actual ping. -	} -	go server.pinger(true) -	return server -} - -var errPoolLimit = errors.New("per-server connection limit reached") -var errServerClosed = errors.New("server was closed") - -// AcquireSocket returns a socket for communicating with the server. -// This will attempt to reuse an old connection, if one is available. Otherwise, -// it will establish a new one. The returned socket is owned by the call site, -// and will return to the cache when the socket has its Release method called -// the same number of times as AcquireSocket + Acquire were called for it. -// If the poolLimit argument is greater than zero and the number of sockets in -// use in this server is greater than the provided limit, errPoolLimit is -// returned. -func (server *mongoServer) AcquireSocket(poolLimit int, timeout time.Duration) (socket *mongoSocket, abended bool, err error) { -	for { -		server.Lock() -		abended = server.abended -		if server.closed { -			server.Unlock() -			return nil, abended, errServerClosed -		} -		n := len(server.unusedSockets) -		if poolLimit > 0 && len(server.liveSockets)-n >= poolLimit { -			server.Unlock() -			return nil, false, errPoolLimit -		} -		if n > 0 { -			socket = server.unusedSockets[n-1] -			server.unusedSockets[n-1] = nil // Help GC. -			server.unusedSockets = server.unusedSockets[:n-1] -			info := server.info -			server.Unlock() -			err = socket.InitialAcquire(info, timeout) -			if err != nil { -				continue -			} -		} else { -			server.Unlock() -			socket, err = server.Connect(timeout) -			if err == nil { -				server.Lock() -				// We've waited for the Connect, see if we got -				// closed in the meantime -				if server.closed { -					server.Unlock() -					socket.Release() -					socket.Close() -					return nil, abended, errServerClosed -				} -				server.liveSockets = append(server.liveSockets, socket) -				server.Unlock() -			} -		} -		return -	} -	panic("unreachable") -} - -// Connect establishes a new connection to the server. This should -// generally be done through server.AcquireSocket(). -func (server *mongoServer) Connect(timeout time.Duration) (*mongoSocket, error) { -	server.RLock() -	master := server.info.Master -	dial := server.dial -	server.RUnlock() - -	logf("Establishing new connection to %s (timeout=%s)...", server.Addr, timeout) -	var conn net.Conn -	var err error -	switch { -	case !dial.isSet(): -		// Cannot do this because it lacks timeout support. :-( -		//conn, err = net.DialTCP("tcp", nil, server.tcpaddr) -		conn, err = net.DialTimeout("tcp", server.ResolvedAddr, timeout) -		if tcpconn, ok := conn.(*net.TCPConn); ok { -			tcpconn.SetKeepAlive(true) -		} else if err == nil { -			panic("internal error: obtained TCP connection is not a *net.TCPConn!?") -		} -	case dial.old != nil: -		conn, err = dial.old(server.tcpaddr) -	case dial.new != nil: -		conn, err = dial.new(&ServerAddr{server.Addr, server.tcpaddr}) -	default: -		panic("dialer is set, but both dial.old and dial.new are nil") -	} -	if err != nil { -		logf("Connection to %s failed: %v", server.Addr, err.Error()) -		return nil, err -	} -	logf("Connection to %s established.", server.Addr) - -	stats.conn(+1, master) -	return newSocket(server, conn, timeout), nil -} - -// Close forces closing all sockets that are alive, whether -// they're currently in use or not. -func (server *mongoServer) Close() { -	server.Lock() -	server.closed = true -	liveSockets := server.liveSockets -	unusedSockets := server.unusedSockets -	server.liveSockets = nil -	server.unusedSockets = nil -	server.Unlock() -	logf("Connections to %s closing (%d live sockets).", server.Addr, len(liveSockets)) -	for i, s := range liveSockets { -		s.Close() -		liveSockets[i] = nil -	} -	for i := range unusedSockets { -		unusedSockets[i] = nil -	} -} - -// RecycleSocket puts socket back into the unused cache. -func (server *mongoServer) RecycleSocket(socket *mongoSocket) { -	server.Lock() -	if !server.closed { -		server.unusedSockets = append(server.unusedSockets, socket) -	} -	server.Unlock() -} - -func removeSocket(sockets []*mongoSocket, socket *mongoSocket) []*mongoSocket { -	for i, s := range sockets { -		if s == socket { -			copy(sockets[i:], sockets[i+1:]) -			n := len(sockets) - 1 -			sockets[n] = nil -			sockets = sockets[:n] -			break -		} -	} -	return sockets -} - -// AbendSocket notifies the server that the given socket has terminated -// abnormally, and thus should be discarded rather than cached. -func (server *mongoServer) AbendSocket(socket *mongoSocket) { -	server.Lock() -	server.abended = true -	if server.closed { -		server.Unlock() -		return -	} -	server.liveSockets = removeSocket(server.liveSockets, socket) -	server.unusedSockets = removeSocket(server.unusedSockets, socket) -	server.Unlock() -	// Maybe just a timeout, but suggest a cluster sync up just in case. -	select { -	case server.sync <- true: -	default: -	} -} - -func (server *mongoServer) SetInfo(info *mongoServerInfo) { -	server.Lock() -	server.info = info -	server.Unlock() -} - -func (server *mongoServer) Info() *mongoServerInfo { -	server.Lock() -	info := server.info -	server.Unlock() -	return info -} - -func (server *mongoServer) hasTags(serverTags []bson.D) bool { -NextTagSet: -	for _, tags := range serverTags { -	NextReqTag: -		for _, req := range tags { -			for _, has := range server.info.Tags { -				if req.Name == has.Name { -					if req.Value == has.Value { -						continue NextReqTag -					} -					continue NextTagSet -				} -			} -			continue NextTagSet -		} -		return true -	} -	return false -} - -var pingDelay = 15 * time.Second - -func (server *mongoServer) pinger(loop bool) { -	var delay time.Duration -	if raceDetector { -		// This variable is only ever touched by tests. -		globalMutex.Lock() -		delay = pingDelay -		globalMutex.Unlock() -	} else { -		delay = pingDelay -	} -	op := queryOp{ -		collection: "admin.$cmd", -		query:      bson.D{{"ping", 1}}, -		flags:      flagSlaveOk, -		limit:      -1, -	} -	for { -		if loop { -			time.Sleep(delay) -		} -		op := op -		socket, _, err := server.AcquireSocket(0, delay) -		if err == nil { -			start := time.Now() -			_, _ = socket.SimpleQuery(&op) -			delay := time.Now().Sub(start) - -			server.pingWindow[server.pingIndex] = delay -			server.pingIndex = (server.pingIndex + 1) % len(server.pingWindow) -			server.pingCount++ -			var max time.Duration -			for i := 0; i < len(server.pingWindow) && uint32(i) < server.pingCount; i++ { -				if server.pingWindow[i] > max { -					max = server.pingWindow[i] -				} -			} -			socket.Release() -			server.Lock() -			if server.closed { -				loop = false -			} -			server.pingValue = max -			server.Unlock() -			logf("Ping for %s is %d ms", server.Addr, max/time.Millisecond) -		} else if err == errServerClosed { -			return -		} -		if !loop { -			return -		} -	} -} - -type mongoServerSlice []*mongoServer - -func (s mongoServerSlice) Len() int { -	return len(s) -} - -func (s mongoServerSlice) Less(i, j int) bool { -	return s[i].ResolvedAddr < s[j].ResolvedAddr -} - -func (s mongoServerSlice) Swap(i, j int) { -	s[i], s[j] = s[j], s[i] -} - -func (s mongoServerSlice) Sort() { -	sort.Sort(s) -} - -func (s mongoServerSlice) Search(resolvedAddr string) (i int, ok bool) { -	n := len(s) -	i = sort.Search(n, func(i int) bool { -		return s[i].ResolvedAddr >= resolvedAddr -	}) -	return i, i != n && s[i].ResolvedAddr == resolvedAddr -} - -type mongoServers struct { -	slice mongoServerSlice -} - -func (servers *mongoServers) Search(resolvedAddr string) (server *mongoServer) { -	if i, ok := servers.slice.Search(resolvedAddr); ok { -		return servers.slice[i] -	} -	return nil -} - -func (servers *mongoServers) Add(server *mongoServer) { -	servers.slice = append(servers.slice, server) -	servers.slice.Sort() -} - -func (servers *mongoServers) Remove(other *mongoServer) (server *mongoServer) { -	if i, found := servers.slice.Search(other.ResolvedAddr); found { -		server = servers.slice[i] -		copy(servers.slice[i:], servers.slice[i+1:]) -		n := len(servers.slice) - 1 -		servers.slice[n] = nil // Help GC. -		servers.slice = servers.slice[:n] -	} -	return -} - -func (servers *mongoServers) Slice() []*mongoServer { -	return ([]*mongoServer)(servers.slice) -} - -func (servers *mongoServers) Get(i int) *mongoServer { -	return servers.slice[i] -} - -func (servers *mongoServers) Len() int { -	return len(servers.slice) -} - -func (servers *mongoServers) Empty() bool { -	return len(servers.slice) == 0 -} - -func (servers *mongoServers) HasMongos() bool { -	for _, s := range servers.slice { -		if s.Info().Mongos { -			return true -		} -	} -	return false -} - -// BestFit returns the best guess of what would be the most interesting -// server to perform operations on at this point in time. -func (servers *mongoServers) BestFit(mode Mode, serverTags []bson.D) *mongoServer { -	var best *mongoServer -	for _, next := range servers.slice { -		if best == nil { -			best = next -			best.RLock() -			if serverTags != nil && !next.info.Mongos && !best.hasTags(serverTags) { -				best.RUnlock() -				best = nil -			} -			continue -		} -		next.RLock() -		swap := false -		switch { -		case serverTags != nil && !next.info.Mongos && !next.hasTags(serverTags): -			// Must have requested tags. -		case mode == Secondary && next.info.Master && !next.info.Mongos: -			// Must be a secondary or mongos. -		case next.info.Master != best.info.Master && mode != Nearest: -			// Prefer slaves, unless the mode is PrimaryPreferred. -			swap = (mode == PrimaryPreferred) != best.info.Master -		case absDuration(next.pingValue-best.pingValue) > 15*time.Millisecond: -			// Prefer nearest server. -			swap = next.pingValue < best.pingValue -		case len(next.liveSockets)-len(next.unusedSockets) < len(best.liveSockets)-len(best.unusedSockets): -			// Prefer servers with less connections. -			swap = true -		} -		if swap { -			best.RUnlock() -			best = next -		} else { -			next.RUnlock() -		} -	} -	if best != nil { -		best.RUnlock() -	} -	return best -} - -func absDuration(d time.Duration) time.Duration { -	if d < 0 { -		return -d -	} -	return d -} diff --git a/vendor/gopkg.in/mgo.v2/session.go b/vendor/gopkg.in/mgo.v2/session.go deleted file mode 100644 index 3dccf36..0000000 --- a/vendor/gopkg.in/mgo.v2/session.go +++ /dev/null @@ -1,4825 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"crypto/md5" -	"encoding/hex" -	"errors" -	"fmt" -	"math" -	"net" -	"net/url" -	"reflect" -	"sort" -	"strconv" -	"strings" -	"sync" -	"time" - -	"gopkg.in/mgo.v2/bson" -) - -type Mode int - -const ( -	// Relevant documentation on read preference modes: -	// -	//     http://docs.mongodb.org/manual/reference/read-preference/ -	// -	Primary            Mode = 2 // Default mode. All operations read from the current replica set primary. -	PrimaryPreferred   Mode = 3 // Read from the primary if available. Read from the secondary otherwise. -	Secondary          Mode = 4 // Read from one of the nearest secondary members of the replica set. -	SecondaryPreferred Mode = 5 // Read from one of the nearest secondaries if available. Read from primary otherwise. -	Nearest            Mode = 6 // Read from one of the nearest members, irrespective of it being primary or secondary. - -	// Read preference modes are specific to mgo: -	Eventual  Mode = 0 // Same as Nearest, but may change servers between reads. -	Monotonic Mode = 1 // Same as SecondaryPreferred before first write. Same as Primary after first write. -	Strong    Mode = 2 // Same as Primary. -) - -// mgo.v3: Drop Strong mode, suffix all modes with "Mode". - -// When changing the Session type, check if newSession and copySession -// need to be updated too. - -// Session represents a communication session with the database. -// -// All Session methods are concurrency-safe and may be called from multiple -// goroutines. In all session modes but Eventual, using the session from -// multiple goroutines will cause them to share the same underlying socket. -// See the documentation on Session.SetMode for more details. -type Session struct { -	m                sync.RWMutex -	cluster_         *mongoCluster -	slaveSocket      *mongoSocket -	masterSocket     *mongoSocket -	slaveOk          bool -	consistency      Mode -	queryConfig      query -	safeOp           *queryOp -	syncTimeout      time.Duration -	sockTimeout      time.Duration -	defaultdb        string -	sourcedb         string -	dialCred         *Credential -	creds            []Credential -	poolLimit        int -	bypassValidation bool -} - -type Database struct { -	Session *Session -	Name    string -} - -type Collection struct { -	Database *Database -	Name     string // "collection" -	FullName string // "db.collection" -} - -type Query struct { -	m       sync.Mutex -	session *Session -	query   // Enables default settings in session. -} - -type query struct { -	op       queryOp -	prefetch float64 -	limit    int32 -} - -type getLastError struct { -	CmdName  int         "getLastError,omitempty" -	W        interface{} "w,omitempty" -	WTimeout int         "wtimeout,omitempty" -	FSync    bool        "fsync,omitempty" -	J        bool        "j,omitempty" -} - -type Iter struct { -	m              sync.Mutex -	gotReply       sync.Cond -	session        *Session -	server         *mongoServer -	docData        queue -	err            error -	op             getMoreOp -	prefetch       float64 -	limit          int32 -	docsToReceive  int -	docsBeforeMore int -	timeout        time.Duration -	timedout       bool -	findCmd        bool -} - -var ( -	ErrNotFound = errors.New("not found") -	ErrCursor   = errors.New("invalid cursor") -) - -const ( -	defaultPrefetch  = 0.25 -	maxUpsertRetries = 5 -) - -// Dial establishes a new session to the cluster identified by the given seed -// server(s). The session will enable communication with all of the servers in -// the cluster, so the seed servers are used only to find out about the cluster -// topology. -// -// Dial will timeout after 10 seconds if a server isn't reached. The returned -// session will timeout operations after one minute by default if servers -// aren't available. To customize the timeout, see DialWithTimeout, -// SetSyncTimeout, and SetSocketTimeout. -// -// This method is generally called just once for a given cluster.  Further -// sessions to the same cluster are then established using the New or Copy -// methods on the obtained session. This will make them share the underlying -// cluster, and manage the pool of connections appropriately. -// -// Once the session is not useful anymore, Close must be called to release the -// resources appropriately. -// -// The seed servers must be provided in the following format: -// -//     [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options] -// -// For example, it may be as simple as: -// -//     localhost -// -// Or more involved like: -// -//     mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb -// -// If the port number is not provided for a server, it defaults to 27017. -// -// The username and password provided in the URL will be used to authenticate -// into the database named after the slash at the end of the host names, or -// into the "admin" database if none is provided.  The authentication information -// will persist in sessions obtained through the New method as well. -// -// The following connection options are supported after the question mark: -// -//     connect=direct -// -//         Disables the automatic replica set server discovery logic, and -//         forces the use of servers provided only (even if secondaries). -//         Note that to talk to a secondary the consistency requirements -//         must be relaxed to Monotonic or Eventual via SetMode. -// -// -//     connect=replicaSet -// -//  	   Discover replica sets automatically. Default connection behavior. -// -// -//     replicaSet=<setname> -// -//         If specified will prevent the obtained session from communicating -//         with any server which is not part of a replica set with the given name. -//         The default is to communicate with any server specified or discovered -//         via the servers contacted. -// -// -//     authSource=<db> -// -//         Informs the database used to establish credentials and privileges -//         with a MongoDB server. Defaults to the database name provided via -//         the URL path, and "admin" if that's unset. -// -// -//     authMechanism=<mechanism> -// -//        Defines the protocol for credential negotiation. Defaults to "MONGODB-CR", -//        which is the default username/password challenge-response mechanism. -// -// -//     gssapiServiceName=<name> -// -//        Defines the service name to use when authenticating with the GSSAPI -//        mechanism. Defaults to "mongodb". -// -// -//     maxPoolSize=<limit> -// -//        Defines the per-server socket pool limit. Defaults to 4096. -//        See Session.SetPoolLimit for details. -// -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/reference/connection-string/ -// -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 -} - -// DialWithTimeout works like Dial, but uses timeout as the amount of time to -// wait for a server to respond when first connecting and also on follow up -// operations in the session. If timeout is zero, the call may block -// forever waiting for a connection to be made. -// -// See SetSyncTimeout for customizing the timeout for the session. -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) -} - -// ParseURL parses a MongoDB URL as accepted by the Dial function and returns -// a value suitable for providing into DialWithInfo. -// -// See Dial for more details on the format of url. -func ParseURL(url string) (*DialInfo, error) { -	uinfo, err := extractURL(url) -	if err != nil { -		return nil, err -	} -	direct := false -	mechanism := "" -	service := "" -	source := "" -	setName := "" -	poolLimit := 0 -	for k, v := range uinfo.options { -		switch k { -		case "authSource": -			source = v -		case "authMechanism": -			mechanism = v -		case "gssapiServiceName": -			service = v -		case "replicaSet": -			setName = v -		case "maxPoolSize": -			poolLimit, err = strconv.Atoi(v) -			if err != nil { -				return nil, errors.New("bad value for maxPoolSize: " + v) -			} -		case "connect": -			if v == "direct" { -				direct = true -				break -			} -			if v == "replicaSet" { -				break -			} -			fallthrough -		default: -			return nil, errors.New("unsupported connection URL option: " + k + "=" + v) -		} -	} -	info := DialInfo{ -		Addrs:          uinfo.addrs, -		Direct:         direct, -		Database:       uinfo.db, -		Username:       uinfo.user, -		Password:       uinfo.pass, -		Mechanism:      mechanism, -		Service:        service, -		Source:         source, -		PoolLimit:      poolLimit, -		ReplicaSetName: setName, -	} -	return &info, nil -} - -// DialInfo holds options for establishing a session with a MongoDB cluster. -// To use a URL, see the Dial function. -type DialInfo struct { -	// Addrs holds the addresses for the seed servers. -	Addrs []string - -	// Direct informs whether to establish connections only with the -	// specified seed servers, or to obtain information for the whole -	// cluster and establish connections with further servers too. -	Direct bool - -	// Timeout is the amount of time to wait for a server to respond when -	// first connecting and on follow up operations in the session. If -	// timeout is zero, the call may block forever waiting for a connection -	// to be established. Timeout does not affect logic in DialServer. -	Timeout time.Duration - -	// FailFast will cause connection and query attempts to fail faster when -	// the server is unavailable, instead of retrying until the configured -	// timeout period. Note that an unavailable server may silently drop -	// packets instead of rejecting them, in which case it's impossible to -	// distinguish it from a slow server, so the timeout stays relevant. -	FailFast bool - -	// Database is the default database name used when the Session.DB method -	// is called with an empty name, and is also used during the initial -	// authentication if Source is unset. -	Database string - -	// ReplicaSetName, if specified, will prevent the obtained session from -	// communicating with any server which is not part of a replica set -	// with the given name. The default is to communicate with any server -	// specified or discovered via the servers contacted. -	ReplicaSetName string - -	// Source is the database used to establish credentials and privileges -	// with a MongoDB server. Defaults to the value of Database, if that is -	// set, or "admin" otherwise. -	Source string - -	// Service defines the service name to use when authenticating with the GSSAPI -	// mechanism. Defaults to "mongodb". -	Service string - -	// ServiceHost defines which hostname to use when authenticating -	// with the GSSAPI mechanism. If not specified, defaults to the MongoDB -	// server's address. -	ServiceHost string - -	// Mechanism defines the protocol for credential negotiation. -	// Defaults to "MONGODB-CR". -	Mechanism string - -	// Username and Password inform the credentials for the initial authentication -	// done on the database defined by the Source field. See Session.Login. -	Username string -	Password string - -	// PoolLimit defines the per-server socket pool limit. Defaults to 4096. -	// See Session.SetPoolLimit for details. -	PoolLimit int - -	// DialServer optionally specifies the dial function for establishing -	// connections with the MongoDB servers. -	DialServer func(addr *ServerAddr) (net.Conn, error) - -	// WARNING: This field is obsolete. See DialServer above. -	Dial func(addr net.Addr) (net.Conn, error) -} - -// mgo.v3: Drop DialInfo.Dial. - -// ServerAddr represents the address for establishing a connection to an -// individual MongoDB server. -type ServerAddr struct { -	str string -	tcp *net.TCPAddr -} - -// String returns the address that was provided for the server before resolution. -func (addr *ServerAddr) String() string { -	return addr.str -} - -// TCPAddr returns the resolved TCP address for the server. -func (addr *ServerAddr) TCPAddr() *net.TCPAddr { -	return addr.tcp -} - -// DialWithInfo establishes a new session to the cluster identified by info. -func DialWithInfo(info *DialInfo) (*Session, error) { -	addrs := make([]string, len(info.Addrs)) -	for i, addr := range info.Addrs { -		p := strings.LastIndexAny(addr, "]:") -		if p == -1 || addr[p] != ':' { -			// XXX This is untested. The test suite doesn't use the standard port. -			addr += ":27017" -		} -		addrs[i] = addr -	} -	cluster := newCluster(addrs, info.Direct, info.FailFast, dialer{info.Dial, info.DialServer}, info.ReplicaSetName) -	session := newSession(Eventual, cluster, info.Timeout) -	session.defaultdb = info.Database -	if session.defaultdb == "" { -		session.defaultdb = "test" -	} -	session.sourcedb = info.Source -	if session.sourcedb == "" { -		session.sourcedb = info.Database -		if session.sourcedb == "" { -			session.sourcedb = "admin" -		} -	} -	if info.Username != "" { -		source := session.sourcedb -		if info.Source == "" && -			(info.Mechanism == "GSSAPI" || info.Mechanism == "PLAIN" || info.Mechanism == "MONGODB-X509") { -			source = "$external" -		} -		session.dialCred = &Credential{ -			Username:    info.Username, -			Password:    info.Password, -			Mechanism:   info.Mechanism, -			Service:     info.Service, -			ServiceHost: info.ServiceHost, -			Source:      source, -		} -		session.creds = []Credential{*session.dialCred} -	} -	if info.PoolLimit > 0 { -		session.poolLimit = info.PoolLimit -	} -	cluster.Release() - -	// People get confused when we return a session that is not actually -	// established to any servers yet (e.g. what if url was wrong). So, -	// ping the server to ensure there's someone there, and abort if it -	// fails. -	if err := session.Ping(); err != nil { -		session.Close() -		return nil, err -	} -	session.SetMode(Strong, true) -	return session, nil -} - -func isOptSep(c rune) bool { -	return c == ';' || c == '&' -} - -type urlInfo struct { -	addrs   []string -	user    string -	pass    string -	db      string -	options map[string]string -} - -func extractURL(s string) (*urlInfo, error) { -	if strings.HasPrefix(s, "mongodb://") { -		s = s[10:] -	} -	info := &urlInfo{options: make(map[string]string)} -	if c := strings.Index(s, "?"); c != -1 { -		for _, pair := range strings.FieldsFunc(s[c+1:], isOptSep) { -			l := strings.SplitN(pair, "=", 2) -			if len(l) != 2 || l[0] == "" || l[1] == "" { -				return nil, errors.New("connection option must be key=value: " + pair) -			} -			info.options[l[0]] = l[1] -		} -		s = s[:c] -	} -	if c := strings.Index(s, "@"); c != -1 { -		pair := strings.SplitN(s[:c], ":", 2) -		if len(pair) > 2 || pair[0] == "" { -			return nil, errors.New("credentials must be provided as user:pass@host") -		} -		var err error -		info.user, err = url.QueryUnescape(pair[0]) -		if err != nil { -			return nil, fmt.Errorf("cannot unescape username in URL: %q", pair[0]) -		} -		if len(pair) > 1 { -			info.pass, err = url.QueryUnescape(pair[1]) -			if err != nil { -				return nil, fmt.Errorf("cannot unescape password in URL") -			} -		} -		s = s[c+1:] -	} -	if c := strings.Index(s, "/"); c != -1 { -		info.db = s[c+1:] -		s = s[:c] -	} -	info.addrs = strings.Split(s, ",") -	return info, nil -} - -func newSession(consistency Mode, cluster *mongoCluster, timeout time.Duration) (session *Session) { -	cluster.Acquire() -	session = &Session{ -		cluster_:    cluster, -		syncTimeout: timeout, -		sockTimeout: timeout, -		poolLimit:   4096, -	} -	debugf("New session %p on cluster %p", session, cluster) -	session.SetMode(consistency, true) -	session.SetSafe(&Safe{}) -	session.queryConfig.prefetch = defaultPrefetch -	return session -} - -func copySession(session *Session, keepCreds bool) (s *Session) { -	cluster := session.cluster() -	cluster.Acquire() -	if session.masterSocket != nil { -		session.masterSocket.Acquire() -	} -	if session.slaveSocket != nil { -		session.slaveSocket.Acquire() -	} -	var creds []Credential -	if keepCreds { -		creds = make([]Credential, len(session.creds)) -		copy(creds, session.creds) -	} else if session.dialCred != nil { -		creds = []Credential{*session.dialCred} -	} -	scopy := *session -	scopy.m = sync.RWMutex{} -	scopy.creds = creds -	s = &scopy -	debugf("New session %p on cluster %p (copy from %p)", s, cluster, session) -	return s -} - -// LiveServers returns a list of server addresses which are -// currently known to be alive. -func (s *Session) LiveServers() (addrs []string) { -	s.m.RLock() -	addrs = s.cluster().LiveServers() -	s.m.RUnlock() -	return addrs -} - -// DB returns a value representing the named database. If name -// is empty, the database name provided in the dialed URL is -// used instead. If that is also empty, "test" is used as a -// fallback in a way equivalent to the mongo shell. -// -// Creating this value is a very lightweight operation, and -// involves no network communication. -func (s *Session) DB(name string) *Database { -	if name == "" { -		name = s.defaultdb -	} -	return &Database{s, name} -} - -// C returns a value representing the named collection. -// -// Creating this value is a very lightweight operation, and -// involves no network communication. -func (db *Database) C(name string) *Collection { -	return &Collection{db, name, db.Name + "." + name} -} - -// With returns a copy of db that uses session s. -func (db *Database) With(s *Session) *Database { -	newdb := *db -	newdb.Session = s -	return &newdb -} - -// With returns a copy of c that uses session s. -func (c *Collection) With(s *Session) *Collection { -	newdb := *c.Database -	newdb.Session = s -	newc := *c -	newc.Database = &newdb -	return &newc -} - -// GridFS returns a GridFS value representing collections in db that -// follow the standard GridFS specification. -// The provided prefix (sometimes known as root) will determine which -// collections to use, and is usually set to "fs" when there is a -// single GridFS in the database. -// -// See the GridFS Create, Open, and OpenId methods for more details. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/GridFS -//     http://www.mongodb.org/display/DOCS/GridFS+Tools -//     http://www.mongodb.org/display/DOCS/GridFS+Specification -// -func (db *Database) GridFS(prefix string) *GridFS { -	return newGridFS(db, prefix) -} - -// Run issues the provided command on the db database and unmarshals -// its result in the respective argument. The cmd argument may be either -// a string with the command name itself, in which case an empty document of -// the form bson.M{cmd: 1} will be used, or it may be a full command document. -// -// Note that MongoDB considers the first marshalled key as the command -// name, so when providing a command with options, it's important to -// use an ordering-preserving document, such as a struct value or an -// instance of bson.D.  For instance: -// -//     db.Run(bson.D{{"create", "mycollection"}, {"size", 1024}}) -// -// For privilleged commands typically run on the "admin" database, see -// the Run method in the Session type. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Commands -//     http://www.mongodb.org/display/DOCS/List+of+Database+CommandSkips -// -func (db *Database) Run(cmd interface{}, result interface{}) error { -	socket, err := db.Session.acquireSocket(true) -	if err != nil { -		return err -	} -	defer socket.Release() - -	// This is an optimized form of db.C("$cmd").Find(cmd).One(result). -	return db.run(socket, cmd, result) -} - -// Credential holds details to authenticate with a MongoDB server. -type Credential struct { -	// Username and Password hold the basic details for authentication. -	// Password is optional with some authentication mechanisms. -	Username string -	Password string - -	// Source is the database used to establish credentials and privileges -	// with a MongoDB server. Defaults to the default database provided -	// during dial, or "admin" if that was unset. -	Source string - -	// Service defines the service name to use when authenticating with the GSSAPI -	// mechanism. Defaults to "mongodb". -	Service string - -	// ServiceHost defines which hostname to use when authenticating -	// with the GSSAPI mechanism. If not specified, defaults to the MongoDB -	// server's address. -	ServiceHost string - -	// Mechanism defines the protocol for credential negotiation. -	// Defaults to "MONGODB-CR". -	Mechanism string -} - -// Login authenticates with MongoDB using the provided credential.  The -// authentication is valid for the whole session and will stay valid until -// Logout is explicitly called for the same database, or the session is -// closed. -func (db *Database) Login(user, pass string) error { -	return db.Session.Login(&Credential{Username: user, Password: pass, Source: db.Name}) -} - -// Login authenticates with MongoDB using the provided credential.  The -// authentication is valid for the whole session and will stay valid until -// Logout is explicitly called for the same database, or the session is -// closed. -func (s *Session) Login(cred *Credential) error { -	socket, err := s.acquireSocket(true) -	if err != nil { -		return err -	} -	defer socket.Release() - -	credCopy := *cred -	if cred.Source == "" { -		if cred.Mechanism == "GSSAPI" { -			credCopy.Source = "$external" -		} else { -			credCopy.Source = s.sourcedb -		} -	} -	err = socket.Login(credCopy) -	if err != nil { -		return err -	} - -	s.m.Lock() -	s.creds = append(s.creds, credCopy) -	s.m.Unlock() -	return nil -} - -func (s *Session) socketLogin(socket *mongoSocket) error { -	for _, cred := range s.creds { -		if err := socket.Login(cred); err != nil { -			return err -		} -	} -	return nil -} - -// Logout removes any established authentication credentials for the database. -func (db *Database) Logout() { -	session := db.Session -	dbname := db.Name -	session.m.Lock() -	found := false -	for i, cred := range session.creds { -		if cred.Source == dbname { -			copy(session.creds[i:], session.creds[i+1:]) -			session.creds = session.creds[:len(session.creds)-1] -			found = true -			break -		} -	} -	if found { -		if session.masterSocket != nil { -			session.masterSocket.Logout(dbname) -		} -		if session.slaveSocket != nil { -			session.slaveSocket.Logout(dbname) -		} -	} -	session.m.Unlock() -} - -// LogoutAll removes all established authentication credentials for the session. -func (s *Session) LogoutAll() { -	s.m.Lock() -	for _, cred := range s.creds { -		if s.masterSocket != nil { -			s.masterSocket.Logout(cred.Source) -		} -		if s.slaveSocket != nil { -			s.slaveSocket.Logout(cred.Source) -		} -	} -	s.creds = s.creds[0:0] -	s.m.Unlock() -} - -// User represents a MongoDB user. -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/reference/privilege-documents/ -//     http://docs.mongodb.org/manual/reference/user-privileges/ -// -type User struct { -	// Username is how the user identifies itself to the system. -	Username string `bson:"user"` - -	// Password is the plaintext password for the user. If set, -	// the UpsertUser method will hash it into PasswordHash and -	// unset it before the user is added to the database. -	Password string `bson:",omitempty"` - -	// PasswordHash is the MD5 hash of Username+":mongo:"+Password. -	PasswordHash string `bson:"pwd,omitempty"` - -	// CustomData holds arbitrary data admins decide to associate -	// with this user, such as the full name or employee id. -	CustomData interface{} `bson:"customData,omitempty"` - -	// Roles indicates the set of roles the user will be provided. -	// See the Role constants. -	Roles []Role `bson:"roles"` - -	// OtherDBRoles allows assigning roles in other databases from -	// user documents inserted in the admin database. This field -	// only works in the admin database. -	OtherDBRoles map[string][]Role `bson:"otherDBRoles,omitempty"` - -	// UserSource indicates where to look for this user's credentials. -	// It may be set to a database name, or to "$external" for -	// consulting an external resource such as Kerberos. UserSource -	// must not be set if Password or PasswordHash are present. -	// -	// WARNING: This setting was only ever supported in MongoDB 2.4, -	// and is now obsolete. -	UserSource string `bson:"userSource,omitempty"` -} - -type Role string - -const ( -	// Relevant documentation: -	// -	//     http://docs.mongodb.org/manual/reference/user-privileges/ -	// -	RoleRoot         Role = "root" -	RoleRead         Role = "read" -	RoleReadAny      Role = "readAnyDatabase" -	RoleReadWrite    Role = "readWrite" -	RoleReadWriteAny Role = "readWriteAnyDatabase" -	RoleDBAdmin      Role = "dbAdmin" -	RoleDBAdminAny   Role = "dbAdminAnyDatabase" -	RoleUserAdmin    Role = "userAdmin" -	RoleUserAdminAny Role = "userAdminAnyDatabase" -	RoleClusterAdmin Role = "clusterAdmin" -) - -// UpsertUser updates the authentication credentials and the roles for -// a MongoDB user within the db database. If the named user doesn't exist -// it will be created. -// -// This method should only be used from MongoDB 2.4 and on. For older -// MongoDB releases, use the obsolete AddUser method instead. -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/reference/user-privileges/ -//     http://docs.mongodb.org/manual/reference/privilege-documents/ -// -func (db *Database) UpsertUser(user *User) error { -	if user.Username == "" { -		return fmt.Errorf("user has no Username") -	} -	if (user.Password != "" || user.PasswordHash != "") && user.UserSource != "" { -		return fmt.Errorf("user has both Password/PasswordHash and UserSource set") -	} -	if len(user.OtherDBRoles) > 0 && db.Name != "admin" && db.Name != "$external" { -		return fmt.Errorf("user with OtherDBRoles is only supported in the admin or $external databases") -	} - -	// Attempt to run this using 2.6+ commands. -	rundb := db -	if user.UserSource != "" { -		// Compatibility logic for the userSource field of MongoDB <= 2.4.X -		rundb = db.Session.DB(user.UserSource) -	} -	err := rundb.runUserCmd("updateUser", user) -	// retry with createUser when isAuthError in order to enable the "localhost exception" -	if isNotFound(err) || isAuthError(err) { -		return rundb.runUserCmd("createUser", user) -	} -	if !isNoCmd(err) { -		return err -	} - -	// Command does not exist. Fallback to pre-2.6 behavior. -	var set, unset bson.D -	if user.Password != "" { -		psum := md5.New() -		psum.Write([]byte(user.Username + ":mongo:" + user.Password)) -		set = append(set, bson.DocElem{"pwd", hex.EncodeToString(psum.Sum(nil))}) -		unset = append(unset, bson.DocElem{"userSource", 1}) -	} else if user.PasswordHash != "" { -		set = append(set, bson.DocElem{"pwd", user.PasswordHash}) -		unset = append(unset, bson.DocElem{"userSource", 1}) -	} -	if user.UserSource != "" { -		set = append(set, bson.DocElem{"userSource", user.UserSource}) -		unset = append(unset, bson.DocElem{"pwd", 1}) -	} -	if user.Roles != nil || user.OtherDBRoles != nil { -		set = append(set, bson.DocElem{"roles", user.Roles}) -		if len(user.OtherDBRoles) > 0 { -			set = append(set, bson.DocElem{"otherDBRoles", user.OtherDBRoles}) -		} else { -			unset = append(unset, bson.DocElem{"otherDBRoles", 1}) -		} -	} -	users := db.C("system.users") -	err = users.Update(bson.D{{"user", user.Username}}, bson.D{{"$unset", unset}, {"$set", set}}) -	if err == ErrNotFound { -		set = append(set, bson.DocElem{"user", user.Username}) -		if user.Roles == nil && user.OtherDBRoles == nil { -			// Roles must be sent, as it's the way MongoDB distinguishes -			// old-style documents from new-style documents in pre-2.6. -			set = append(set, bson.DocElem{"roles", user.Roles}) -		} -		err = users.Insert(set) -	} -	return err -} - -func isNoCmd(err error) bool { -	e, ok := err.(*QueryError) -	return ok && (e.Code == 59 || e.Code == 13390 || strings.HasPrefix(e.Message, "no such cmd:")) -} - -func isNotFound(err error) bool { -	e, ok := err.(*QueryError) -	return ok && e.Code == 11 -} - -func isAuthError(err error) bool { -	e, ok := err.(*QueryError) -	return ok && e.Code == 13 -} - -func (db *Database) runUserCmd(cmdName string, user *User) error { -	cmd := make(bson.D, 0, 16) -	cmd = append(cmd, bson.DocElem{cmdName, user.Username}) -	if user.Password != "" { -		cmd = append(cmd, bson.DocElem{"pwd", user.Password}) -	} -	var roles []interface{} -	for _, role := range user.Roles { -		roles = append(roles, role) -	} -	for db, dbroles := range user.OtherDBRoles { -		for _, role := range dbroles { -			roles = append(roles, bson.D{{"role", role}, {"db", db}}) -		} -	} -	if roles != nil || user.Roles != nil || cmdName == "createUser" { -		cmd = append(cmd, bson.DocElem{"roles", roles}) -	} -	err := db.Run(cmd, nil) -	if !isNoCmd(err) && user.UserSource != "" && (user.UserSource != "$external" || db.Name != "$external") { -		return fmt.Errorf("MongoDB 2.6+ does not support the UserSource setting") -	} -	return err -} - -// AddUser creates or updates the authentication credentials of user within -// the db database. -// -// WARNING: This method is obsolete and should only be used with MongoDB 2.2 -// or earlier. For MongoDB 2.4 and on, use UpsertUser instead. -func (db *Database) AddUser(username, password string, readOnly bool) error { -	// Try to emulate the old behavior on 2.6+ -	user := &User{Username: username, Password: password} -	if db.Name == "admin" { -		if readOnly { -			user.Roles = []Role{RoleReadAny} -		} else { -			user.Roles = []Role{RoleReadWriteAny} -		} -	} else { -		if readOnly { -			user.Roles = []Role{RoleRead} -		} else { -			user.Roles = []Role{RoleReadWrite} -		} -	} -	err := db.runUserCmd("updateUser", user) -	if isNotFound(err) { -		return db.runUserCmd("createUser", user) -	} -	if !isNoCmd(err) { -		return err -	} - -	// Command doesn't exist. Fallback to pre-2.6 behavior. -	psum := md5.New() -	psum.Write([]byte(username + ":mongo:" + password)) -	digest := hex.EncodeToString(psum.Sum(nil)) -	c := db.C("system.users") -	_, err = c.Upsert(bson.M{"user": username}, bson.M{"$set": bson.M{"user": username, "pwd": digest, "readOnly": readOnly}}) -	return err -} - -// RemoveUser removes the authentication credentials of user from the database. -func (db *Database) RemoveUser(user string) error { -	err := db.Run(bson.D{{"dropUser", user}}, nil) -	if isNoCmd(err) { -		users := db.C("system.users") -		return users.Remove(bson.M{"user": user}) -	} -	if isNotFound(err) { -		return ErrNotFound -	} -	return err -} - -type indexSpec struct { -	Name, NS         string -	Key              bson.D -	Unique           bool    ",omitempty" -	DropDups         bool    "dropDups,omitempty" -	Background       bool    ",omitempty" -	Sparse           bool    ",omitempty" -	Bits             int     ",omitempty" -	Min, Max         float64 ",omitempty" -	BucketSize       float64 "bucketSize,omitempty" -	ExpireAfter      int     "expireAfterSeconds,omitempty" -	Weights          bson.D  ",omitempty" -	DefaultLanguage  string  "default_language,omitempty" -	LanguageOverride string  "language_override,omitempty" -	TextIndexVersion int     "textIndexVersion,omitempty" - -	Collation *Collation "collation,omitempty" -} - -type Index struct { -	Key        []string // Index key fields; prefix name with dash (-) for descending order -	Unique     bool     // Prevent two documents from having the same index key -	DropDups   bool     // Drop documents with the same index key as a previously indexed one -	Background bool     // Build index in background and return immediately -	Sparse     bool     // Only index documents containing the Key fields - -	// If ExpireAfter is defined the server will periodically delete -	// documents with indexed time.Time older than the provided delta. -	ExpireAfter time.Duration - -	// Name holds the stored index name. On creation if this field is unset it is -	// computed by EnsureIndex based on the index key. -	Name string - -	// Properties for spatial indexes. -	// -	// Min and Max were improperly typed as int when they should have been -	// floats.  To preserve backwards compatibility they are still typed as -	// int and the following two fields enable reading and writing the same -	// fields as float numbers. In mgo.v3, these fields will be dropped and -	// Min/Max will become floats. -	Min, Max   int -	Minf, Maxf float64 -	BucketSize float64 -	Bits       int - -	// Properties for text indexes. -	DefaultLanguage  string -	LanguageOverride string - -	// Weights defines the significance of provided fields relative to other -	// fields in a text index. The score for a given word in a document is derived -	// from the weighted sum of the frequency for each of the indexed fields in -	// that document. The default field weight is 1. -	Weights map[string]int - -	// Collation defines the collation to use for the index. -	Collation *Collation -} - -type Collation struct { - -	// Locale defines the collation locale. -	Locale string `bson:"locale"` - -	// CaseLevel defines whether to turn case sensitivity on at strength 1 or 2. -	CaseLevel bool `bson:"caseLevel,omitempty"` - -	// CaseFirst may be set to "upper" or "lower" to define whether -	// to have uppercase or lowercase items first. Default is "off". -	CaseFirst string `bson:"caseFirst,omitempty"` - -	// Strength defines the priority of comparison properties, as follows: -	// -	//   1 (primary)    - Strongest level, denote difference between base characters -	//   2 (secondary)  - Accents in characters are considered secondary differences -	//   3 (tertiary)   - Upper and lower case differences in characters are -	//                    distinguished at the tertiary level -	//   4 (quaternary) - When punctuation is ignored at level 1-3, an additional -	//                    level can be used to distinguish words with and without -	//                    punctuation. Should only be used if ignoring punctuation -	//                    is required or when processing Japanese text. -	//   5 (identical)  - When all other levels are equal, the identical level is -	//                    used as a tiebreaker. The Unicode code point values of -	//                    the NFD form of each string are compared at this level, -	//                    just in case there is no difference at levels 1-4 -	// -	// Strength defaults to 3. -	Strength int `bson:"strength,omitempty"` - -	// NumericOrdering defines whether to order numbers based on numerical -	// order and not collation order. -	NumericOrdering bool `bson:"numericOrdering,omitempty"` - -	// Alternate controls whether spaces and punctuation are considered base characters. -	// May be set to "non-ignorable" (spaces and punctuation considered base characters) -	// or "shifted" (spaces and punctuation not considered base characters, and only -	// distinguished at strength > 3). Defaults to "non-ignorable". -	Alternate string `bson:"alternate,omitempty"` - -	// Backwards defines whether to have secondary differences considered in reverse order, -	// as done in the French language. -	Backwards bool `bson:"backwards,omitempty"` -} - -// mgo.v3: Drop Minf and Maxf and transform Min and Max to floats. -// mgo.v3: Drop DropDups as it's unsupported past 2.8. - -type indexKeyInfo struct { -	name    string -	key     bson.D -	weights bson.D -} - -func parseIndexKey(key []string) (*indexKeyInfo, error) { -	var keyInfo indexKeyInfo -	isText := false -	var order interface{} -	for _, field := range key { -		raw := field -		if keyInfo.name != "" { -			keyInfo.name += "_" -		} -		var kind string -		if field != "" { -			if field[0] == '$' { -				if c := strings.Index(field, ":"); c > 1 && c < len(field)-1 { -					kind = field[1:c] -					field = field[c+1:] -					keyInfo.name += field + "_" + kind -				} else { -					field = "\x00" -				} -			} -			switch field[0] { -			case 0: -				// Logic above failed. Reset and error. -				field = "" -			case '@': -				order = "2d" -				field = field[1:] -				// The shell used to render this field as key_ instead of key_2d, -				// and mgo followed suit. This has been fixed in recent server -				// releases, and mgo followed as well. -				keyInfo.name += field + "_2d" -			case '-': -				order = -1 -				field = field[1:] -				keyInfo.name += field + "_-1" -			case '+': -				field = field[1:] -				fallthrough -			default: -				if kind == "" { -					order = 1 -					keyInfo.name += field + "_1" -				} else { -					order = kind -				} -			} -		} -		if field == "" || kind != "" && order != kind { -			return nil, fmt.Errorf(`invalid index key: want "[$<kind>:][-]<field name>", got %q`, raw) -		} -		if kind == "text" { -			if !isText { -				keyInfo.key = append(keyInfo.key, bson.DocElem{"_fts", "text"}, bson.DocElem{"_ftsx", 1}) -				isText = true -			} -			keyInfo.weights = append(keyInfo.weights, bson.DocElem{field, 1}) -		} else { -			keyInfo.key = append(keyInfo.key, bson.DocElem{field, order}) -		} -	} -	if keyInfo.name == "" { -		return nil, errors.New("invalid index key: no fields provided") -	} -	return &keyInfo, nil -} - -// EnsureIndexKey ensures an index with the given key exists, creating it -// if necessary. -// -// This example: -// -//     err := collection.EnsureIndexKey("a", "b") -// -// Is equivalent to: -// -//     err := collection.EnsureIndex(mgo.Index{Key: []string{"a", "b"}}) -// -// See the EnsureIndex method for more details. -func (c *Collection) EnsureIndexKey(key ...string) error { -	return c.EnsureIndex(Index{Key: key}) -} - -// EnsureIndex ensures an index with the given key exists, creating it with -// the provided parameters if necessary. EnsureIndex does not modify a previously -// existent index with a matching key. The old index must be dropped first instead. -// -// Once EnsureIndex returns successfully, following requests for the same index -// will not contact the server unless Collection.DropIndex is used to drop the -// same index, or Session.ResetIndexCache is called. -// -// For example: -// -//     index := Index{ -//         Key: []string{"lastname", "firstname"}, -//         Unique: true, -//         DropDups: true, -//         Background: true, // See notes. -//         Sparse: true, -//     } -//     err := collection.EnsureIndex(index) -// -// The Key value determines which fields compose the index. The index ordering -// will be ascending by default.  To obtain an index with a descending order, -// the field name should be prefixed by a dash (e.g. []string{"-time"}). It can -// also be optionally prefixed by an index kind, as in "$text:summary" or -// "$2d:-point". The key string format is: -// -//     [$<kind>:][-]<field name> -// -// If the Unique field is true, the index must necessarily contain only a single -// document per Key.  With DropDups set to true, documents with the same key -// as a previously indexed one will be dropped rather than an error returned. -// -// If Background is true, other connections will be allowed to proceed using -// the collection without the index while it's being built. Note that the -// session executing EnsureIndex will be blocked for as long as it takes for -// the index to be built. -// -// If Sparse is true, only documents containing the provided Key fields will be -// included in the index.  When using a sparse index for sorting, only indexed -// documents will be returned. -// -// If ExpireAfter is non-zero, the server will periodically scan the collection -// and remove documents containing an indexed time.Time field with a value -// older than ExpireAfter. See the documentation for details: -// -//     http://docs.mongodb.org/manual/tutorial/expire-data -// -// Other kinds of indexes are also supported through that API. Here is an example: -// -//     index := Index{ -//         Key: []string{"$2d:loc"}, -//         Bits: 26, -//     } -//     err := collection.EnsureIndex(index) -// -// The example above requests the creation of a "2d" index for the "loc" field. -// -// The 2D index bounds may be changed using the Min and Max attributes of the -// Index value.  The default bound setting of (-180, 180) is suitable for -// latitude/longitude pairs. -// -// The Bits parameter sets the precision of the 2D geohash values.  If not -// provided, 26 bits are used, which is roughly equivalent to 1 foot of -// precision for the default (-180, 180) index bounds. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Indexes -//     http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ -//     http://www.mongodb.org/display/DOCS/Indexing+as+a+Background+Operation -//     http://www.mongodb.org/display/DOCS/Geospatial+Indexing -//     http://www.mongodb.org/display/DOCS/Multikeys -// -func (c *Collection) EnsureIndex(index Index) error { -	keyInfo, err := parseIndexKey(index.Key) -	if err != nil { -		return err -	} - -	session := c.Database.Session -	cacheKey := c.FullName + "\x00" + keyInfo.name -	if session.cluster().HasCachedIndex(cacheKey) { -		return nil -	} - -	spec := indexSpec{ -		Name:             keyInfo.name, -		NS:               c.FullName, -		Key:              keyInfo.key, -		Unique:           index.Unique, -		DropDups:         index.DropDups, -		Background:       index.Background, -		Sparse:           index.Sparse, -		Bits:             index.Bits, -		Min:              index.Minf, -		Max:              index.Maxf, -		BucketSize:       index.BucketSize, -		ExpireAfter:      int(index.ExpireAfter / time.Second), -		Weights:          keyInfo.weights, -		DefaultLanguage:  index.DefaultLanguage, -		LanguageOverride: index.LanguageOverride, -		Collation:        index.Collation, -	} - -	if spec.Min == 0 && spec.Max == 0 { -		spec.Min = float64(index.Min) -		spec.Max = float64(index.Max) -	} - -	if index.Name != "" { -		spec.Name = index.Name -	} - -NextField: -	for name, weight := range index.Weights { -		for i, elem := range spec.Weights { -			if elem.Name == name { -				spec.Weights[i].Value = weight -				continue NextField -			} -		} -		panic("weight provided for field that is not part of index key: " + name) -	} - -	cloned := session.Clone() -	defer cloned.Close() -	cloned.SetMode(Strong, false) -	cloned.EnsureSafe(&Safe{}) -	db := c.Database.With(cloned) - -	// Try with a command first. -	err = db.Run(bson.D{{"createIndexes", c.Name}, {"indexes", []indexSpec{spec}}}, nil) -	if isNoCmd(err) { -		// Command not yet supported. Insert into the indexes collection instead. -		err = db.C("system.indexes").Insert(&spec) -	} -	if err == nil { -		session.cluster().CacheIndex(cacheKey, true) -	} -	return err -} - -// DropIndex drops the index with the provided key from the c collection. -// -// See EnsureIndex for details on the accepted key variants. -// -// For example: -// -//     err1 := collection.DropIndex("firstField", "-secondField") -//     err2 := collection.DropIndex("customIndexName") -// -func (c *Collection) DropIndex(key ...string) error { -	keyInfo, err := parseIndexKey(key) -	if err != nil { -		return err -	} - -	session := c.Database.Session -	cacheKey := c.FullName + "\x00" + keyInfo.name -	session.cluster().CacheIndex(cacheKey, false) - -	session = session.Clone() -	defer session.Close() -	session.SetMode(Strong, false) - -	db := c.Database.With(session) -	result := struct { -		ErrMsg string -		Ok     bool -	}{} -	err = db.Run(bson.D{{"dropIndexes", c.Name}, {"index", keyInfo.name}}, &result) -	if err != nil { -		return err -	} -	if !result.Ok { -		return errors.New(result.ErrMsg) -	} -	return nil -} - -// DropIndexName removes the index with the provided index name. -// -// For example: -// -//     err := collection.DropIndex("customIndexName") -// -func (c *Collection) DropIndexName(name string) error { -	session := c.Database.Session - -	session = session.Clone() -	defer session.Close() -	session.SetMode(Strong, false) - -	c = c.With(session) - -	indexes, err := c.Indexes() -	if err != nil { -		return err -	} - -	var index Index -	for _, idx := range indexes { -		if idx.Name == name { -			index = idx -			break -		} -	} - -	if index.Name != "" { -		keyInfo, err := parseIndexKey(index.Key) -		if err != nil { -			return err -		} - -		cacheKey := c.FullName + "\x00" + keyInfo.name -		session.cluster().CacheIndex(cacheKey, false) -	} - -	result := struct { -		ErrMsg string -		Ok     bool -	}{} -	err = c.Database.Run(bson.D{{"dropIndexes", c.Name}, {"index", name}}, &result) -	if err != nil { -		return err -	} -	if !result.Ok { -		return errors.New(result.ErrMsg) -	} -	return nil -} - -// nonEventual returns a clone of session and ensures it is not Eventual. -// This guarantees that the server that is used for queries may be reused -// afterwards when a cursor is received. -func (session *Session) nonEventual() *Session { -	cloned := session.Clone() -	if cloned.consistency == Eventual { -		cloned.SetMode(Monotonic, false) -	} -	return cloned -} - -// Indexes returns a list of all indexes for the collection. -// -// For example, this snippet would drop all available indexes: -// -//   indexes, err := collection.Indexes() -//   if err != nil { -//       return err -//   } -//   for _, index := range indexes { -//       err = collection.DropIndex(index.Key...) -//       if err != nil { -//           return err -//       } -//   } -// -// See the EnsureIndex method for more details on indexes. -func (c *Collection) Indexes() (indexes []Index, err error) { -	cloned := c.Database.Session.nonEventual() -	defer cloned.Close() - -	batchSize := int(cloned.queryConfig.op.limit) - -	// Try with a command. -	var result struct { -		Indexes []bson.Raw -		Cursor  cursorData -	} -	var iter *Iter -	err = c.Database.With(cloned).Run(bson.D{{"listIndexes", c.Name}, {"cursor", bson.D{{"batchSize", batchSize}}}}, &result) -	if err == nil { -		firstBatch := result.Indexes -		if firstBatch == nil { -			firstBatch = result.Cursor.FirstBatch -		} -		ns := strings.SplitN(result.Cursor.NS, ".", 2) -		if len(ns) < 2 { -			iter = c.With(cloned).NewIter(nil, firstBatch, result.Cursor.Id, nil) -		} else { -			iter = cloned.DB(ns[0]).C(ns[1]).NewIter(nil, firstBatch, result.Cursor.Id, nil) -		} -	} else if isNoCmd(err) { -		// Command not yet supported. Query the database instead. -		iter = c.Database.C("system.indexes").Find(bson.M{"ns": c.FullName}).Iter() -	} else { -		return nil, err -	} - -	var spec indexSpec -	for iter.Next(&spec) { -		indexes = append(indexes, indexFromSpec(spec)) -	} -	if err = iter.Close(); err != nil { -		return nil, err -	} -	sort.Sort(indexSlice(indexes)) -	return indexes, nil -} - -func indexFromSpec(spec indexSpec) Index { -	index := Index{ -		Name:             spec.Name, -		Key:              simpleIndexKey(spec.Key), -		Unique:           spec.Unique, -		DropDups:         spec.DropDups, -		Background:       spec.Background, -		Sparse:           spec.Sparse, -		Minf:             spec.Min, -		Maxf:             spec.Max, -		Bits:             spec.Bits, -		BucketSize:       spec.BucketSize, -		DefaultLanguage:  spec.DefaultLanguage, -		LanguageOverride: spec.LanguageOverride, -		ExpireAfter:      time.Duration(spec.ExpireAfter) * time.Second, -		Collation:        spec.Collation, -	} -	if float64(int(spec.Min)) == spec.Min && float64(int(spec.Max)) == spec.Max { -		index.Min = int(spec.Min) -		index.Max = int(spec.Max) -	} -	if spec.TextIndexVersion > 0 { -		index.Key = make([]string, len(spec.Weights)) -		index.Weights = make(map[string]int) -		for i, elem := range spec.Weights { -			index.Key[i] = "$text:" + elem.Name -			if w, ok := elem.Value.(int); ok { -				index.Weights[elem.Name] = w -			} -		} -	} -	return index -} - -type indexSlice []Index - -func (idxs indexSlice) Len() int           { return len(idxs) } -func (idxs indexSlice) Less(i, j int) bool { return idxs[i].Name < idxs[j].Name } -func (idxs indexSlice) Swap(i, j int)      { idxs[i], idxs[j] = idxs[j], idxs[i] } - -func simpleIndexKey(realKey bson.D) (key []string) { -	for i := range realKey { -		field := realKey[i].Name -		vi, ok := realKey[i].Value.(int) -		if !ok { -			vf, _ := realKey[i].Value.(float64) -			vi = int(vf) -		} -		if vi == 1 { -			key = append(key, field) -			continue -		} -		if vi == -1 { -			key = append(key, "-"+field) -			continue -		} -		if vs, ok := realKey[i].Value.(string); ok { -			key = append(key, "$"+vs+":"+field) -			continue -		} -		panic("Got unknown index key type for field " + field) -	} -	return -} - -// ResetIndexCache() clears the cache of previously ensured indexes. -// Following requests to EnsureIndex will contact the server. -func (s *Session) ResetIndexCache() { -	s.cluster().ResetIndexCache() -} - -// New creates a new session with the same parameters as the original -// session, including consistency, batch size, prefetching, safety mode, -// etc. The returned session will use sockets from the pool, so there's -// a chance that writes just performed in another session may not yet -// be visible. -// -// Login information from the original session will not be copied over -// into the new session unless it was provided through the initial URL -// for the Dial function. -// -// See the Copy and Clone methods. -// -func (s *Session) New() *Session { -	s.m.Lock() -	scopy := copySession(s, false) -	s.m.Unlock() -	scopy.Refresh() -	return scopy -} - -// Copy works just like New, but preserves the exact authentication -// information from the original session. -func (s *Session) Copy() *Session { -	s.m.Lock() -	scopy := copySession(s, true) -	s.m.Unlock() -	scopy.Refresh() -	return scopy -} - -// Clone works just like Copy, but also reuses the same socket as the original -// session, in case it had already reserved one due to its consistency -// guarantees.  This behavior ensures that writes performed in the old session -// are necessarily observed when using the new session, as long as it was a -// strong or monotonic session.  That said, it also means that long operations -// may cause other goroutines using the original session to wait. -func (s *Session) Clone() *Session { -	s.m.Lock() -	scopy := copySession(s, true) -	s.m.Unlock() -	return scopy -} - -// Close terminates the session.  It's a runtime error to use a session -// after it has been closed. -func (s *Session) Close() { -	s.m.Lock() -	if s.cluster_ != nil { -		debugf("Closing session %p", s) -		s.unsetSocket() -		s.cluster_.Release() -		s.cluster_ = nil -	} -	s.m.Unlock() -} - -func (s *Session) cluster() *mongoCluster { -	if s.cluster_ == nil { -		panic("Session already closed") -	} -	return s.cluster_ -} - -// Refresh puts back any reserved sockets in use and restarts the consistency -// guarantees according to the current consistency setting for the session. -func (s *Session) Refresh() { -	s.m.Lock() -	s.slaveOk = s.consistency != Strong -	s.unsetSocket() -	s.m.Unlock() -} - -// SetMode changes the consistency mode for the session. -// -// The default mode is Strong. -// -// In the Strong consistency mode reads and writes will always be made to -// the primary server using a unique connection so that reads and writes are -// fully consistent, ordered, and observing the most up-to-date data. -// This offers the least benefits in terms of distributing load, but the -// most guarantees.  See also Monotonic and Eventual. -// -// In the Monotonic consistency mode reads may not be entirely up-to-date, -// but they will always see the history of changes moving forward, the data -// read will be consistent across sequential queries in the same session, -// and modifications made within the session will be observed in following -// queries (read-your-writes). -// -// In practice, the Monotonic mode is obtained by performing initial reads -// on a unique connection to an arbitrary secondary, if one is available, -// and once the first write happens, the session connection is switched over -// to the primary server.  This manages to distribute some of the reading -// load with secondaries, while maintaining some useful guarantees. -// -// In the Eventual consistency mode reads will be made to any secondary in the -// cluster, if one is available, and sequential reads will not necessarily -// be made with the same connection.  This means that data may be observed -// out of order.  Writes will of course be issued to the primary, but -// independent writes in the same Eventual session may also be made with -// independent connections, so there are also no guarantees in terms of -// write ordering (no read-your-writes guarantees either). -// -// The Eventual mode is the fastest and most resource-friendly, but is -// also the one offering the least guarantees about ordering of the data -// read and written. -// -// If refresh is true, in addition to ensuring the session is in the given -// consistency mode, the consistency guarantees will also be reset (e.g. -// a Monotonic session will be allowed to read from secondaries again). -// This is equivalent to calling the Refresh function. -// -// Shifting between Monotonic and Strong modes will keep a previously -// reserved connection for the session unless refresh is true or the -// connection is unsuitable (to a secondary server in a Strong session). -func (s *Session) SetMode(consistency Mode, refresh bool) { -	s.m.Lock() -	debugf("Session %p: setting mode %d with refresh=%v (master=%p, slave=%p)", s, consistency, refresh, s.masterSocket, s.slaveSocket) -	s.consistency = consistency -	if refresh { -		s.slaveOk = s.consistency != Strong -		s.unsetSocket() -	} else if s.consistency == Strong { -		s.slaveOk = false -	} else if s.masterSocket == nil { -		s.slaveOk = true -	} -	s.m.Unlock() -} - -// Mode returns the current consistency mode for the session. -func (s *Session) Mode() Mode { -	s.m.RLock() -	mode := s.consistency -	s.m.RUnlock() -	return mode -} - -// SetSyncTimeout sets the amount of time an operation with this session -// will wait before returning an error in case a connection to a usable -// server can't be established. Set it to zero to wait forever. The -// default value is 7 seconds. -func (s *Session) SetSyncTimeout(d time.Duration) { -	s.m.Lock() -	s.syncTimeout = d -	s.m.Unlock() -} - -// SetSocketTimeout sets the amount of time to wait for a non-responding -// socket to the database before it is forcefully closed. -// -// The default timeout is 1 minute. -func (s *Session) SetSocketTimeout(d time.Duration) { -	s.m.Lock() -	s.sockTimeout = d -	if s.masterSocket != nil { -		s.masterSocket.SetTimeout(d) -	} -	if s.slaveSocket != nil { -		s.slaveSocket.SetTimeout(d) -	} -	s.m.Unlock() -} - -// SetCursorTimeout changes the standard timeout period that the server -// enforces on created cursors. The only supported value right now is -// 0, which disables the timeout. The standard server timeout is 10 minutes. -func (s *Session) SetCursorTimeout(d time.Duration) { -	s.m.Lock() -	if d == 0 { -		s.queryConfig.op.flags |= flagNoCursorTimeout -	} else { -		panic("SetCursorTimeout: only 0 (disable timeout) supported for now") -	} -	s.m.Unlock() -} - -// SetPoolLimit sets the maximum number of sockets in use in a single server -// before this session will block waiting for a socket to be available. -// The default limit is 4096. -// -// This limit must be set to cover more than any expected workload of the -// application. It is a bad practice and an unsupported use case to use the -// database driver to define the concurrency limit of an application. Prevent -// such concurrency "at the door" instead, by properly restricting the amount -// of used resources and number of goroutines before they are created. -func (s *Session) SetPoolLimit(limit int) { -	s.m.Lock() -	s.poolLimit = limit -	s.m.Unlock() -} - -// SetBypassValidation sets whether the server should bypass the registered -// validation expressions executed when documents are inserted or modified, -// in the interest of preserving invariants in the collection being modified. -// The default is to not bypass, and thus to perform the validation -// expressions registered for modified collections. -// -// Document validation was introuced in MongoDB 3.2. -// -// Relevant documentation: -// -//   https://docs.mongodb.org/manual/release-notes/3.2/#bypass-validation -// -func (s *Session) SetBypassValidation(bypass bool) { -	s.m.Lock() -	s.bypassValidation = bypass -	s.m.Unlock() -} - -// SetBatch sets the default batch size used when fetching documents from the -// database. It's possible to change this setting on a per-query basis as -// well, using the Query.Batch method. -// -// The default batch size is defined by the database itself.  As of this -// writing, MongoDB will use an initial size of min(100 docs, 4MB) on the -// first batch, and 4MB on remaining ones. -func (s *Session) SetBatch(n int) { -	if n == 1 { -		// Server interprets 1 as -1 and closes the cursor (!?) -		n = 2 -	} -	s.m.Lock() -	s.queryConfig.op.limit = int32(n) -	s.m.Unlock() -} - -// SetPrefetch sets the default point at which the next batch of results will be -// requested.  When there are p*batch_size remaining documents cached in an -// Iter, the next batch will be requested in background. For instance, when -// using this: -// -//     session.SetBatch(200) -//     session.SetPrefetch(0.25) -// -// and there are only 50 documents cached in the Iter to be processed, the -// next batch of 200 will be requested. It's possible to change this setting on -// a per-query basis as well, using the Prefetch method of Query. -// -// The default prefetch value is 0.25. -func (s *Session) SetPrefetch(p float64) { -	s.m.Lock() -	s.queryConfig.prefetch = p -	s.m.Unlock() -} - -// See SetSafe for details on the Safe type. -type Safe struct { -	W        int    // Min # of servers to ack before success -	WMode    string // Write mode for MongoDB 2.0+ (e.g. "majority") -	WTimeout int    // Milliseconds to wait for W before timing out -	FSync    bool   // Sync via the journal if present, or via data files sync otherwise -	J        bool   // Sync via the journal if present -} - -// Safe returns the current safety mode for the session. -func (s *Session) Safe() (safe *Safe) { -	s.m.Lock() -	defer s.m.Unlock() -	if s.safeOp != nil { -		cmd := s.safeOp.query.(*getLastError) -		safe = &Safe{WTimeout: cmd.WTimeout, FSync: cmd.FSync, J: cmd.J} -		switch w := cmd.W.(type) { -		case string: -			safe.WMode = w -		case int: -			safe.W = w -		} -	} -	return -} - -// SetSafe changes the session safety mode. -// -// If the safe parameter is nil, the session is put in unsafe mode, and writes -// become fire-and-forget, without error checking.  The unsafe mode is faster -// since operations won't hold on waiting for a confirmation. -// -// If the safe parameter is not nil, any changing query (insert, update, ...) -// will be followed by a getLastError command with the specified parameters, -// to ensure the request was correctly processed. -// -// The default is &Safe{}, meaning check for errors and use the default -// behavior for all fields. -// -// The safe.W parameter determines how many servers should confirm a write -// before the operation is considered successful.  If set to 0 or 1, the -// command will return as soon as the primary is done with the request. -// If safe.WTimeout is greater than zero, it determines how many milliseconds -// to wait for the safe.W servers to respond before returning an error. -// -// Starting with MongoDB 2.0.0 the safe.WMode parameter can be used instead -// of W to request for richer semantics. If set to "majority" the server will -// wait for a majority of members from the replica set to respond before -// returning. Custom modes may also be defined within the server to create -// very detailed placement schemas. See the data awareness documentation in -// the links below for more details (note that MongoDB internally reuses the -// "w" field name for WMode). -// -// If safe.J is true, servers will block until write operations have been -// committed to the journal. Cannot be used in combination with FSync. Prior -// to MongoDB 2.6 this option was ignored if the server was running without -// journaling. Starting with MongoDB 2.6 write operations will fail with an -// exception if this option is used when the server is running without -// journaling. -// -// If safe.FSync is true and the server is running without journaling, blocks -// until the server has synced all data files to disk. If the server is running -// with journaling, this acts the same as the J option, blocking until write -// operations have been committed to the journal. Cannot be used in -// combination with J. -// -// Since MongoDB 2.0.0, the safe.J option can also be used instead of FSync -// to force the server to wait for a group commit in case journaling is -// enabled. The option has no effect if the server has journaling disabled. -// -// For example, the following statement will make the session check for -// errors, without imposing further constraints: -// -//     session.SetSafe(&mgo.Safe{}) -// -// The following statement will force the server to wait for a majority of -// members of a replica set to return (MongoDB 2.0+ only): -// -//     session.SetSafe(&mgo.Safe{WMode: "majority"}) -// -// The following statement, on the other hand, ensures that at least two -// servers have flushed the change to disk before confirming the success -// of operations: -// -//     session.EnsureSafe(&mgo.Safe{W: 2, FSync: true}) -// -// The following statement, on the other hand, disables the verification -// of errors entirely: -// -//     session.SetSafe(nil) -// -// See also the EnsureSafe method. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/getLastError+Command -//     http://www.mongodb.org/display/DOCS/Verifying+Propagation+of+Writes+with+getLastError -//     http://www.mongodb.org/display/DOCS/Data+Center+Awareness -// -func (s *Session) SetSafe(safe *Safe) { -	s.m.Lock() -	s.safeOp = nil -	s.ensureSafe(safe) -	s.m.Unlock() -} - -// EnsureSafe compares the provided safety parameters with the ones -// currently in use by the session and picks the most conservative -// choice for each setting. -// -// That is: -// -//     - safe.WMode is always used if set. -//     - safe.W is used if larger than the current W and WMode is empty. -//     - safe.FSync is always used if true. -//     - safe.J is used if FSync is false. -//     - safe.WTimeout is used if set and smaller than the current WTimeout. -// -// For example, the following statement will ensure the session is -// at least checking for errors, without enforcing further constraints. -// If a more conservative SetSafe or EnsureSafe call was previously done, -// the following call will be ignored. -// -//     session.EnsureSafe(&mgo.Safe{}) -// -// See also the SetSafe method for details on what each option means. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/getLastError+Command -//     http://www.mongodb.org/display/DOCS/Verifying+Propagation+of+Writes+with+getLastError -//     http://www.mongodb.org/display/DOCS/Data+Center+Awareness -// -func (s *Session) EnsureSafe(safe *Safe) { -	s.m.Lock() -	s.ensureSafe(safe) -	s.m.Unlock() -} - -func (s *Session) ensureSafe(safe *Safe) { -	if safe == nil { -		return -	} - -	var w interface{} -	if safe.WMode != "" { -		w = safe.WMode -	} else if safe.W > 0 { -		w = safe.W -	} - -	var cmd getLastError -	if s.safeOp == nil { -		cmd = getLastError{1, w, safe.WTimeout, safe.FSync, safe.J} -	} else { -		// Copy.  We don't want to mutate the existing query. -		cmd = *(s.safeOp.query.(*getLastError)) -		if cmd.W == nil { -			cmd.W = w -		} else if safe.WMode != "" { -			cmd.W = safe.WMode -		} else if i, ok := cmd.W.(int); ok && safe.W > i { -			cmd.W = safe.W -		} -		if safe.WTimeout > 0 && safe.WTimeout < cmd.WTimeout { -			cmd.WTimeout = safe.WTimeout -		} -		if safe.FSync { -			cmd.FSync = true -			cmd.J = false -		} else if safe.J && !cmd.FSync { -			cmd.J = true -		} -	} -	s.safeOp = &queryOp{ -		query:      &cmd, -		collection: "admin.$cmd", -		limit:      -1, -	} -} - -// Run issues the provided command on the "admin" database and -// and unmarshals its result in the respective argument. The cmd -// argument may be either a string with the command name itself, in -// which case an empty document of the form bson.M{cmd: 1} will be used, -// or it may be a full command document. -// -// Note that MongoDB considers the first marshalled key as the command -// name, so when providing a command with options, it's important to -// use an ordering-preserving document, such as a struct value or an -// instance of bson.D.  For instance: -// -//     db.Run(bson.D{{"create", "mycollection"}, {"size", 1024}}) -// -// For commands on arbitrary databases, see the Run method in -// the Database type. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Commands -//     http://www.mongodb.org/display/DOCS/List+of+Database+CommandSkips -// -func (s *Session) Run(cmd interface{}, result interface{}) error { -	return s.DB("admin").Run(cmd, result) -} - -// SelectServers restricts communication to servers configured with the -// given tags. For example, the following statement restricts servers -// used for reading operations to those with both tag "disk" set to -// "ssd" and tag "rack" set to 1: -// -//     session.SelectServers(bson.D{{"disk", "ssd"}, {"rack", 1}}) -// -// Multiple sets of tags may be provided, in which case the used server -// must match all tags within any one set. -// -// If a connection was previously assigned to the session due to the -// current session mode (see Session.SetMode), the tag selection will -// only be enforced after the session is refreshed. -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/tutorial/configure-replica-set-tag-sets -// -func (s *Session) SelectServers(tags ...bson.D) { -	s.m.Lock() -	s.queryConfig.op.serverTags = tags -	s.m.Unlock() -} - -// Ping runs a trivial ping command just to get in touch with the server. -func (s *Session) Ping() error { -	return s.Run("ping", nil) -} - -// Fsync flushes in-memory writes to disk on the server the session -// is established with. If async is true, the call returns immediately, -// otherwise it returns after the flush has been made. -func (s *Session) Fsync(async bool) error { -	return s.Run(bson.D{{"fsync", 1}, {"async", async}}, nil) -} - -// FsyncLock locks all writes in the specific server the session is -// established with and returns. Any writes attempted to the server -// after it is successfully locked will block until FsyncUnlock is -// called for the same server. -// -// This method works on secondaries as well, preventing the oplog from -// being flushed while the server is locked, but since only the server -// connected to is locked, for locking specific secondaries it may be -// necessary to establish a connection directly to the secondary (see -// Dial's connect=direct option). -// -// As an important caveat, note that once a write is attempted and -// blocks, follow up reads will block as well due to the way the -// lock is internally implemented in the server. More details at: -// -//     https://jira.mongodb.org/browse/SERVER-4243 -// -// FsyncLock is often used for performing consistent backups of -// the database files on disk. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/fsync+Command -//     http://www.mongodb.org/display/DOCS/Backups -// -func (s *Session) FsyncLock() error { -	return s.Run(bson.D{{"fsync", 1}, {"lock", true}}, nil) -} - -// FsyncUnlock releases the server for writes. See FsyncLock for details. -func (s *Session) FsyncUnlock() error { -	err := s.Run(bson.D{{"fsyncUnlock", 1}}, nil) -	if isNoCmd(err) { -		err = s.DB("admin").C("$cmd.sys.unlock").Find(nil).One(nil) // WTF? -	} -	return err -} - -// Find prepares a query using the provided document.  The document may be a -// map or a struct value capable of being marshalled with bson.  The map -// may be a generic one using interface{} for its key and/or values, such as -// bson.M, or it may be a properly typed map.  Providing nil as the document -// is equivalent to providing an empty document such as bson.M{}. -// -// Further details of the query may be tweaked using the resulting Query value, -// and then executed to retrieve results using methods such as One, For, -// Iter, or Tail. -// -// In case the resulting document includes a field named $err or errmsg, which -// are standard ways for MongoDB to return query errors, the returned err will -// be set to a *QueryError value including the Err message and the Code.  In -// those cases, the result argument is still unmarshalled into with the -// received document so that any other custom values may be obtained if -// desired. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Querying -//     http://www.mongodb.org/display/DOCS/Advanced+Queries -// -func (c *Collection) Find(query interface{}) *Query { -	session := c.Database.Session -	session.m.RLock() -	q := &Query{session: session, query: session.queryConfig} -	session.m.RUnlock() -	q.op.query = query -	q.op.collection = c.FullName -	return q -} - -type repairCmd struct { -	RepairCursor string           `bson:"repairCursor"` -	Cursor       *repairCmdCursor ",omitempty" -} - -type repairCmdCursor struct { -	BatchSize int `bson:"batchSize,omitempty"` -} - -// Repair returns an iterator that goes over all recovered documents in the -// collection, in a best-effort manner. This is most useful when there are -// damaged data files. Multiple copies of the same document may be returned -// by the iterator. -// -// Repair is supported in MongoDB 2.7.8 and later. -func (c *Collection) Repair() *Iter { -	// Clone session and set it to Monotonic mode so that the server -	// used for the query may be safely obtained afterwards, if -	// necessary for iteration when a cursor is received. -	session := c.Database.Session -	cloned := session.nonEventual() -	defer cloned.Close() - -	batchSize := int(cloned.queryConfig.op.limit) - -	var result struct{ Cursor cursorData } - -	cmd := repairCmd{ -		RepairCursor: c.Name, -		Cursor:       &repairCmdCursor{batchSize}, -	} - -	clonedc := c.With(cloned) -	err := clonedc.Database.Run(cmd, &result) -	return clonedc.NewIter(session, result.Cursor.FirstBatch, result.Cursor.Id, err) -} - -// FindId is a convenience helper equivalent to: -// -//     query := collection.Find(bson.M{"_id": id}) -// -// See the Find method for more details. -func (c *Collection) FindId(id interface{}) *Query { -	return c.Find(bson.D{{"_id", id}}) -} - -type Pipe struct { -	session    *Session -	collection *Collection -	pipeline   interface{} -	allowDisk  bool -	batchSize  int -} - -type pipeCmd struct { -	Aggregate string -	Pipeline  interface{} -	Cursor    *pipeCmdCursor ",omitempty" -	Explain   bool           ",omitempty" -	AllowDisk bool           "allowDiskUse,omitempty" -} - -type pipeCmdCursor struct { -	BatchSize int `bson:"batchSize,omitempty"` -} - -// Pipe prepares a pipeline to aggregate. The pipeline document -// must be a slice built in terms of the aggregation framework language. -// -// For example: -// -//     pipe := collection.Pipe([]bson.M{{"$match": bson.M{"name": "Otavio"}}}) -//     iter := pipe.Iter() -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/reference/aggregation -//     http://docs.mongodb.org/manual/applications/aggregation -//     http://docs.mongodb.org/manual/tutorial/aggregation-examples -// -func (c *Collection) Pipe(pipeline interface{}) *Pipe { -	session := c.Database.Session -	session.m.RLock() -	batchSize := int(session.queryConfig.op.limit) -	session.m.RUnlock() -	return &Pipe{ -		session:    session, -		collection: c, -		pipeline:   pipeline, -		batchSize:  batchSize, -	} -} - -// Iter executes the pipeline and returns an iterator capable of going -// over all the generated results. -func (p *Pipe) Iter() *Iter { -	// Clone session and set it to Monotonic mode so that the server -	// used for the query may be safely obtained afterwards, if -	// necessary for iteration when a cursor is received. -	cloned := p.session.nonEventual() -	defer cloned.Close() -	c := p.collection.With(cloned) - -	var result struct { -		Result []bson.Raw // 2.4, no cursors. -		Cursor cursorData // 2.6+, with cursors. -	} - -	cmd := pipeCmd{ -		Aggregate: c.Name, -		Pipeline:  p.pipeline, -		AllowDisk: p.allowDisk, -		Cursor:    &pipeCmdCursor{p.batchSize}, -	} -	err := c.Database.Run(cmd, &result) -	if e, ok := err.(*QueryError); ok && e.Message == `unrecognized field "cursor` { -		cmd.Cursor = nil -		cmd.AllowDisk = false -		err = c.Database.Run(cmd, &result) -	} -	firstBatch := result.Result -	if firstBatch == nil { -		firstBatch = result.Cursor.FirstBatch -	} -	return c.NewIter(p.session, firstBatch, result.Cursor.Id, err) -} - -// NewIter returns a newly created iterator with the provided parameters. -// Using this method is not recommended unless the desired functionality -// is not yet exposed via a more convenient interface (Find, Pipe, etc). -// -// The optional session parameter associates the lifetime of the returned -// iterator to an arbitrary session. If nil, the iterator will be bound to -// c's session. -// -// Documents in firstBatch will be individually provided by the returned -// iterator before documents from cursorId are made available. If cursorId -// is zero, only the documents in firstBatch are provided. -// -// If err is not nil, the iterator's Err method will report it after -// exhausting documents in firstBatch. -// -// NewIter must be called right after the cursor id is obtained, and must not -// be called on a collection in Eventual mode, because the cursor id is -// associated with the specific server that returned it. The provided session -// parameter may be in any mode or state, though. -// -func (c *Collection) NewIter(session *Session, firstBatch []bson.Raw, cursorId int64, err error) *Iter { -	var server *mongoServer -	csession := c.Database.Session -	csession.m.RLock() -	socket := csession.masterSocket -	if socket == nil { -		socket = csession.slaveSocket -	} -	if socket != nil { -		server = socket.Server() -	} -	csession.m.RUnlock() - -	if server == nil { -		if csession.Mode() == Eventual { -			panic("Collection.NewIter called in Eventual mode") -		} -		if err == nil { -			err = errors.New("server not available") -		} -	} - -	if session == nil { -		session = csession -	} - -	iter := &Iter{ -		session: session, -		server:  server, -		timeout: -1, -		err:     err, -	} -	iter.gotReply.L = &iter.m -	for _, doc := range firstBatch { -		iter.docData.Push(doc.Data) -	} -	if cursorId != 0 { -		iter.op.cursorId = cursorId -		iter.op.collection = c.FullName -		iter.op.replyFunc = iter.replyFunc() -	} -	return iter -} - -// All works like Iter.All. -func (p *Pipe) All(result interface{}) error { -	return p.Iter().All(result) -} - -// One executes the pipeline and unmarshals the first item from the -// result set into the result parameter. -// It returns ErrNotFound if no items are generated by the pipeline. -func (p *Pipe) One(result interface{}) error { -	iter := p.Iter() -	if iter.Next(result) { -		return nil -	} -	if err := iter.Err(); err != nil { -		return err -	} -	return ErrNotFound -} - -// Explain returns a number of details about how the MongoDB server would -// execute the requested pipeline, such as the number of objects examined, -// the number of times the read lock was yielded to allow writes to go in, -// and so on. -// -// For example: -// -//     var m bson.M -//     err := collection.Pipe(pipeline).Explain(&m) -//     if err == nil { -//         fmt.Printf("Explain: %#v\n", m) -//     } -// -func (p *Pipe) Explain(result interface{}) error { -	c := p.collection -	cmd := pipeCmd{ -		Aggregate: c.Name, -		Pipeline:  p.pipeline, -		AllowDisk: p.allowDisk, -		Explain:   true, -	} -	return c.Database.Run(cmd, result) -} - -// AllowDiskUse enables writing to the "<dbpath>/_tmp" server directory so -// that aggregation pipelines do not have to be held entirely in memory. -func (p *Pipe) AllowDiskUse() *Pipe { -	p.allowDisk = true -	return p -} - -// Batch sets the batch size used when fetching documents from the database. -// It's possible to change this setting on a per-session basis as well, using -// the Batch method of Session. -// -// The default batch size is defined by the database server. -func (p *Pipe) Batch(n int) *Pipe { -	p.batchSize = n -	return p -} - -// mgo.v3: Use a single user-visible error type. - -type LastError struct { -	Err             string -	Code, N, Waited int -	FSyncFiles      int `bson:"fsyncFiles"` -	WTimeout        bool -	UpdatedExisting bool        `bson:"updatedExisting"` -	UpsertedId      interface{} `bson:"upserted"` - -	modified int -	ecases   []BulkErrorCase -} - -func (err *LastError) Error() string { -	return err.Err -} - -type queryError struct { -	Err           string "$err" -	ErrMsg        string -	Assertion     string -	Code          int -	AssertionCode int "assertionCode" -} - -type QueryError struct { -	Code      int -	Message   string -	Assertion bool -} - -func (err *QueryError) Error() string { -	return err.Message -} - -// IsDup returns whether err informs of a duplicate key error because -// a primary key index or a secondary unique index already has an entry -// with the given value. -func IsDup(err error) bool { -	// Besides being handy, helps with MongoDB bugs SERVER-7164 and SERVER-11493. -	// What follows makes me sad. Hopefully conventions will be more clear over time. -	switch e := err.(type) { -	case *LastError: -		return e.Code == 11000 || e.Code == 11001 || e.Code == 12582 || e.Code == 16460 && strings.Contains(e.Err, " E11000 ") -	case *QueryError: -		return e.Code == 11000 || e.Code == 11001 || e.Code == 12582 -	case *BulkError: -		for _, ecase := range e.ecases { -			if !IsDup(ecase.Err) { -				return false -			} -		} -		return true -	} -	return false -} - -// Insert inserts one or more documents in the respective collection.  In -// case the session is in safe mode (see the SetSafe method) and an error -// happens while inserting the provided documents, the returned error will -// be of type *LastError. -func (c *Collection) Insert(docs ...interface{}) error { -	_, err := c.writeOp(&insertOp{c.FullName, docs, 0}, true) -	return err -} - -// Update finds a single document matching the provided selector document -// and modifies it according to the update document. -// If the session is in safe mode (see SetSafe) a ErrNotFound error is -// returned if a document isn't found, or a value of type *LastError -// when some other error is detected. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Updating -//     http://www.mongodb.org/display/DOCS/Atomic+Operations -// -func (c *Collection) Update(selector interface{}, update interface{}) error { -	if selector == nil { -		selector = bson.D{} -	} -	op := updateOp{ -		Collection: c.FullName, -		Selector:   selector, -		Update:     update, -	} -	lerr, err := c.writeOp(&op, true) -	if err == nil && lerr != nil && !lerr.UpdatedExisting { -		return ErrNotFound -	} -	return err -} - -// UpdateId is a convenience helper equivalent to: -// -//     err := collection.Update(bson.M{"_id": id}, update) -// -// See the Update method for more details. -func (c *Collection) UpdateId(id interface{}, update interface{}) error { -	return c.Update(bson.D{{"_id", id}}, update) -} - -// ChangeInfo holds details about the outcome of an update operation. -type ChangeInfo struct { -	// Updated reports the number of existing documents modified. -	// Due to server limitations, this reports the same value as the Matched field when -	// talking to MongoDB <= 2.4 and on Upsert and Apply (findAndModify) operations. -	Updated    int -	Removed    int         // Number of documents removed -	Matched    int         // Number of documents matched but not necessarily changed -	UpsertedId interface{} // Upserted _id field, when not explicitly provided -} - -// UpdateAll finds all documents matching the provided selector document -// and modifies them according to the update document. -// If the session is in safe mode (see SetSafe) details of the executed -// operation are returned in info or an error of type *LastError when -// some problem is detected. It is not an error for the update to not be -// applied on any documents because the selector doesn't match. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Updating -//     http://www.mongodb.org/display/DOCS/Atomic+Operations -// -func (c *Collection) UpdateAll(selector interface{}, update interface{}) (info *ChangeInfo, err error) { -	if selector == nil { -		selector = bson.D{} -	} -	op := updateOp{ -		Collection: c.FullName, -		Selector:   selector, -		Update:     update, -		Flags:      2, -		Multi:      true, -	} -	lerr, err := c.writeOp(&op, true) -	if err == nil && lerr != nil { -		info = &ChangeInfo{Updated: lerr.modified, Matched: lerr.N} -	} -	return info, err -} - -// Upsert finds a single document matching the provided selector document -// and modifies it according to the update document.  If no document matching -// the selector is found, the update document is applied to the selector -// document and the result is inserted in the collection. -// If the session is in safe mode (see SetSafe) details of the executed -// operation are returned in info, or an error of type *LastError when -// some problem is detected. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Updating -//     http://www.mongodb.org/display/DOCS/Atomic+Operations -// -func (c *Collection) Upsert(selector interface{}, update interface{}) (info *ChangeInfo, err error) { -	if selector == nil { -		selector = bson.D{} -	} -	op := updateOp{ -		Collection: c.FullName, -		Selector:   selector, -		Update:     update, -		Flags:      1, -		Upsert:     true, -	} -	var lerr *LastError -	for i := 0; i < maxUpsertRetries; i++ { -		lerr, err = c.writeOp(&op, true) -		// Retry duplicate key errors on upserts. -		// https://docs.mongodb.com/v3.2/reference/method/db.collection.update/#use-unique-indexes -		if !IsDup(err) { -			break -		} -	} -	if err == nil && lerr != nil { -		info = &ChangeInfo{} -		if lerr.UpdatedExisting { -			info.Matched = lerr.N -			info.Updated = lerr.modified -		} else { -			info.UpsertedId = lerr.UpsertedId -		} -	} -	return info, err -} - -// UpsertId is a convenience helper equivalent to: -// -//     info, err := collection.Upsert(bson.M{"_id": id}, update) -// -// See the Upsert method for more details. -func (c *Collection) UpsertId(id interface{}, update interface{}) (info *ChangeInfo, err error) { -	return c.Upsert(bson.D{{"_id", id}}, update) -} - -// Remove finds a single document matching the provided selector document -// and removes it from the database. -// If the session is in safe mode (see SetSafe) a ErrNotFound error is -// returned if a document isn't found, or a value of type *LastError -// when some other error is detected. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Removing -// -func (c *Collection) Remove(selector interface{}) error { -	if selector == nil { -		selector = bson.D{} -	} -	lerr, err := c.writeOp(&deleteOp{c.FullName, selector, 1, 1}, true) -	if err == nil && lerr != nil && lerr.N == 0 { -		return ErrNotFound -	} -	return err -} - -// RemoveId is a convenience helper equivalent to: -// -//     err := collection.Remove(bson.M{"_id": id}) -// -// See the Remove method for more details. -func (c *Collection) RemoveId(id interface{}) error { -	return c.Remove(bson.D{{"_id", id}}) -} - -// RemoveAll finds all documents matching the provided selector document -// and removes them from the database.  In case the session is in safe mode -// (see the SetSafe method) and an error happens when attempting the change, -// the returned error will be of type *LastError. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Removing -// -func (c *Collection) RemoveAll(selector interface{}) (info *ChangeInfo, err error) { -	if selector == nil { -		selector = bson.D{} -	} -	lerr, err := c.writeOp(&deleteOp{c.FullName, selector, 0, 0}, true) -	if err == nil && lerr != nil { -		info = &ChangeInfo{Removed: lerr.N, Matched: lerr.N} -	} -	return info, err -} - -// DropDatabase removes the entire database including all of its collections. -func (db *Database) DropDatabase() error { -	return db.Run(bson.D{{"dropDatabase", 1}}, nil) -} - -// DropCollection removes the entire collection including all of its documents. -func (c *Collection) DropCollection() error { -	return c.Database.Run(bson.D{{"drop", c.Name}}, nil) -} - -// The CollectionInfo type holds metadata about a collection. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/createCollection+Command -//     http://www.mongodb.org/display/DOCS/Capped+Collections -// -type CollectionInfo struct { -	// DisableIdIndex prevents the automatic creation of the index -	// on the _id field for the collection. -	DisableIdIndex bool - -	// ForceIdIndex enforces the automatic creation of the index -	// on the _id field for the collection. Capped collections, -	// for example, do not have such an index by default. -	ForceIdIndex bool - -	// If Capped is true new documents will replace old ones when -	// the collection is full. MaxBytes must necessarily be set -	// to define the size when the collection wraps around. -	// MaxDocs optionally defines the number of documents when it -	// wraps, but MaxBytes still needs to be set. -	Capped   bool -	MaxBytes int -	MaxDocs  int - -	// Validator contains a validation expression that defines which -	// documents should be considered valid for this collection. -	Validator interface{} - -	// ValidationLevel may be set to "strict" (the default) to force -	// MongoDB to validate all documents on inserts and updates, to -	// "moderate" to apply the validation rules only to documents -	// that already fulfill the validation criteria, or to "off" for -	// disabling validation entirely. -	ValidationLevel string - -	// ValidationAction determines how MongoDB handles documents that -	// violate the validation rules. It may be set to "error" (the default) -	// to reject inserts or updates that violate the rules, or to "warn" -	// to log invalid operations but allow them to proceed. -	ValidationAction string - -	// StorageEngine allows specifying collection options for the -	// storage engine in use. The map keys must hold the storage engine -	// name for which options are being specified. -	StorageEngine interface{} -} - -// Create explicitly creates the c collection with details of info. -// MongoDB creates collections automatically on use, so this method -// is only necessary when creating collection with non-default -// characteristics, such as capped collections. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/createCollection+Command -//     http://www.mongodb.org/display/DOCS/Capped+Collections -// -func (c *Collection) Create(info *CollectionInfo) error { -	cmd := make(bson.D, 0, 4) -	cmd = append(cmd, bson.DocElem{"create", c.Name}) -	if info.Capped { -		if info.MaxBytes < 1 { -			return fmt.Errorf("Collection.Create: with Capped, MaxBytes must also be set") -		} -		cmd = append(cmd, bson.DocElem{"capped", true}) -		cmd = append(cmd, bson.DocElem{"size", info.MaxBytes}) -		if info.MaxDocs > 0 { -			cmd = append(cmd, bson.DocElem{"max", info.MaxDocs}) -		} -	} -	if info.DisableIdIndex { -		cmd = append(cmd, bson.DocElem{"autoIndexId", false}) -	} -	if info.ForceIdIndex { -		cmd = append(cmd, bson.DocElem{"autoIndexId", true}) -	} -	if info.Validator != nil { -		cmd = append(cmd, bson.DocElem{"validator", info.Validator}) -	} -	if info.ValidationLevel != "" { -		cmd = append(cmd, bson.DocElem{"validationLevel", info.ValidationLevel}) -	} -	if info.ValidationAction != "" { -		cmd = append(cmd, bson.DocElem{"validationAction", info.ValidationAction}) -	} -	if info.StorageEngine != nil { -		cmd = append(cmd, bson.DocElem{"storageEngine", info.StorageEngine}) -	} -	return c.Database.Run(cmd, nil) -} - -// Batch sets the batch size used when fetching documents from the database. -// It's possible to change this setting on a per-session basis as well, using -// the Batch method of Session. - -// The default batch size is defined by the database itself.  As of this -// writing, MongoDB will use an initial size of min(100 docs, 4MB) on the -// first batch, and 4MB on remaining ones. -func (q *Query) Batch(n int) *Query { -	if n == 1 { -		// Server interprets 1 as -1 and closes the cursor (!?) -		n = 2 -	} -	q.m.Lock() -	q.op.limit = int32(n) -	q.m.Unlock() -	return q -} - -// Prefetch sets the point at which the next batch of results will be requested. -// When there are p*batch_size remaining documents cached in an Iter, the next -// batch will be requested in background. For instance, when using this: -// -//     query.Batch(200).Prefetch(0.25) -// -// and there are only 50 documents cached in the Iter to be processed, the -// next batch of 200 will be requested. It's possible to change this setting on -// a per-session basis as well, using the SetPrefetch method of Session. -// -// The default prefetch value is 0.25. -func (q *Query) Prefetch(p float64) *Query { -	q.m.Lock() -	q.prefetch = p -	q.m.Unlock() -	return q -} - -// Skip skips over the n initial documents from the query results.  Note that -// this only makes sense with capped collections where documents are naturally -// ordered by insertion time, or with sorted results. -func (q *Query) Skip(n int) *Query { -	q.m.Lock() -	q.op.skip = int32(n) -	q.m.Unlock() -	return q -} - -// Limit restricts the maximum number of documents retrieved to n, and also -// changes the batch size to the same value.  Once n documents have been -// returned by Next, the following call will return ErrNotFound. -func (q *Query) Limit(n int) *Query { -	q.m.Lock() -	switch { -	case n == 1: -		q.limit = 1 -		q.op.limit = -1 -	case n == math.MinInt32: // -MinInt32 == -MinInt32 -		q.limit = math.MaxInt32 -		q.op.limit = math.MinInt32 + 1 -	case n < 0: -		q.limit = int32(-n) -		q.op.limit = int32(n) -	default: -		q.limit = int32(n) -		q.op.limit = int32(n) -	} -	q.m.Unlock() -	return q -} - -// Select enables selecting which fields should be retrieved for the results -// found. For example, the following query would only retrieve the name field: -// -//     err := collection.Find(nil).Select(bson.M{"name": 1}).One(&result) -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields -// -func (q *Query) Select(selector interface{}) *Query { -	q.m.Lock() -	q.op.selector = selector -	q.m.Unlock() -	return q -} - -// Sort asks the database to order returned documents according to the -// provided field names. A field name may be prefixed by - (minus) for -// it to be sorted in reverse order. -// -// For example: -// -//     query1 := collection.Find(nil).Sort("firstname", "lastname") -//     query2 := collection.Find(nil).Sort("-age") -//     query3 := collection.Find(nil).Sort("$natural") -//     query4 := collection.Find(nil).Select(bson.M{"score": bson.M{"$meta": "textScore"}}).Sort("$textScore:score") -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order -// -func (q *Query) Sort(fields ...string) *Query { -	q.m.Lock() -	var order bson.D -	for _, field := range fields { -		n := 1 -		var kind string -		if field != "" { -			if field[0] == '$' { -				if c := strings.Index(field, ":"); c > 1 && c < len(field)-1 { -					kind = field[1:c] -					field = field[c+1:] -				} -			} -			switch field[0] { -			case '+': -				field = field[1:] -			case '-': -				n = -1 -				field = field[1:] -			} -		} -		if field == "" { -			panic("Sort: empty field name") -		} -		if kind == "textScore" { -			order = append(order, bson.DocElem{field, bson.M{"$meta": kind}}) -		} else { -			order = append(order, bson.DocElem{field, n}) -		} -	} -	q.op.options.OrderBy = order -	q.op.hasOptions = true -	q.m.Unlock() -	return q -} - -// Explain returns a number of details about how the MongoDB server would -// execute the requested query, such as the number of objects examined, -// the number of times the read lock was yielded to allow writes to go in, -// and so on. -// -// For example: -// -//     m := bson.M{} -//     err := collection.Find(bson.M{"filename": name}).Explain(m) -//     if err == nil { -//         fmt.Printf("Explain: %#v\n", m) -//     } -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Optimization -//     http://www.mongodb.org/display/DOCS/Query+Optimizer -// -func (q *Query) Explain(result interface{}) error { -	q.m.Lock() -	clone := &Query{session: q.session, query: q.query} -	q.m.Unlock() -	clone.op.options.Explain = true -	clone.op.hasOptions = true -	if clone.op.limit > 0 { -		clone.op.limit = -q.op.limit -	} -	iter := clone.Iter() -	if iter.Next(result) { -		return nil -	} -	return iter.Close() -} - -// TODO: Add Collection.Explain. See https://goo.gl/1MDlvz. - -// Hint will include an explicit "hint" in the query to force the server -// to use a specified index, potentially improving performance in some -// situations.  The provided parameters are the fields that compose the -// key of the index to be used.  For details on how the indexKey may be -// built, see the EnsureIndex method. -// -// For example: -// -//     query := collection.Find(bson.M{"firstname": "Joe", "lastname": "Winter"}) -//     query.Hint("lastname", "firstname") -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Optimization -//     http://www.mongodb.org/display/DOCS/Query+Optimizer -// -func (q *Query) Hint(indexKey ...string) *Query { -	q.m.Lock() -	keyInfo, err := parseIndexKey(indexKey) -	q.op.options.Hint = keyInfo.key -	q.op.hasOptions = true -	q.m.Unlock() -	if err != nil { -		panic(err) -	} -	return q -} - -// SetMaxScan constrains the query to stop after scanning the specified -// number of documents. -// -// This modifier is generally used to prevent potentially long running -// queries from disrupting performance by scanning through too much data. -func (q *Query) SetMaxScan(n int) *Query { -	q.m.Lock() -	q.op.options.MaxScan = n -	q.op.hasOptions = true -	q.m.Unlock() -	return q -} - -// SetMaxTime constrains the query to stop after running for the specified time. -// -// When the time limit is reached MongoDB automatically cancels the query. -// This can be used to efficiently prevent and identify unexpectedly slow queries. -// -// A few important notes about the mechanism enforcing this limit: -// -//  - Requests can block behind locking operations on the server, and that blocking -//    time is not accounted for. In other words, the timer starts ticking only after -//    the actual start of the query when it initially acquires the appropriate lock; -// -//  - Operations are interrupted only at interrupt points where an operation can be -//    safely aborted – the total execution time may exceed the specified value; -// -//  - The limit can be applied to both CRUD operations and commands, but not all -//    commands are interruptible; -// -//  - While iterating over results, computing follow up batches is included in the -//    total time and the iteration continues until the alloted time is over, but -//    network roundtrips are not taken into account for the limit. -// -//  - This limit does not override the inactive cursor timeout for idle cursors -//    (default is 10 min). -// -// This mechanism was introduced in MongoDB 2.6. -// -// Relevant documentation: -// -//   http://blog.mongodb.org/post/83621787773/maxtimems-and-query-optimizer-introspection-in -// -func (q *Query) SetMaxTime(d time.Duration) *Query { -	q.m.Lock() -	q.op.options.MaxTimeMS = int(d / time.Millisecond) -	q.op.hasOptions = true -	q.m.Unlock() -	return q -} - -// Snapshot will force the performed query to make use of an available -// index on the _id field to prevent the same document from being returned -// more than once in a single iteration. This might happen without this -// setting in situations when the document changes in size and thus has to -// be moved while the iteration is running. -// -// Because snapshot mode traverses the _id index, it may not be used with -// sorting or explicit hints. It also cannot use any other index for the -// query. -// -// Even with snapshot mode, items inserted or deleted during the query may -// or may not be returned; that is, this mode is not a true point-in-time -// snapshot. -// -// The same effect of Snapshot may be obtained by using any unique index on -// field(s) that will not be modified (best to use Hint explicitly too). -// A non-unique index (such as creation time) may be made unique by -// appending _id to the index when creating it. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database -// -func (q *Query) Snapshot() *Query { -	q.m.Lock() -	q.op.options.Snapshot = true -	q.op.hasOptions = true -	q.m.Unlock() -	return q -} - -// Comment adds a comment to the query to identify it in the database profiler output. -// -// Relevant documentation: -// -//     http://docs.mongodb.org/manual/reference/operator/meta/comment -//     http://docs.mongodb.org/manual/reference/command/profile -//     http://docs.mongodb.org/manual/administration/analyzing-mongodb-performance/#database-profiling -// -func (q *Query) Comment(comment string) *Query { -	q.m.Lock() -	q.op.options.Comment = comment -	q.op.hasOptions = true -	q.m.Unlock() -	return q -} - -// LogReplay enables an option that optimizes queries that are typically -// made on the MongoDB oplog for replaying it. This is an internal -// implementation aspect and most likely uninteresting for other uses. -// It has seen at least one use case, though, so it's exposed via the API. -func (q *Query) LogReplay() *Query { -	q.m.Lock() -	q.op.flags |= flagLogReplay -	q.m.Unlock() -	return q -} - -func checkQueryError(fullname string, d []byte) error { -	l := len(d) -	if l < 16 { -		return nil -	} -	if d[5] == '$' && d[6] == 'e' && d[7] == 'r' && d[8] == 'r' && d[9] == '\x00' && d[4] == '\x02' { -		goto Error -	} -	if len(fullname) < 5 || fullname[len(fullname)-5:] != ".$cmd" { -		return nil -	} -	for i := 0; i+8 < l; i++ { -		if d[i] == '\x02' && d[i+1] == 'e' && d[i+2] == 'r' && d[i+3] == 'r' && d[i+4] == 'm' && d[i+5] == 's' && d[i+6] == 'g' && d[i+7] == '\x00' { -			goto Error -		} -	} -	return nil - -Error: -	result := &queryError{} -	bson.Unmarshal(d, result) -	if result.Err == "" && result.ErrMsg == "" { -		return nil -	} -	if result.AssertionCode != 0 && result.Assertion != "" { -		return &QueryError{Code: result.AssertionCode, Message: result.Assertion, Assertion: true} -	} -	if result.Err != "" { -		return &QueryError{Code: result.Code, Message: result.Err} -	} -	return &QueryError{Code: result.Code, Message: result.ErrMsg} -} - -// One executes the query and unmarshals the first obtained document into the -// result argument.  The result must be a struct or map value capable of being -// unmarshalled into by gobson.  This function blocks until either a result -// is available or an error happens.  For example: -// -//     err := collection.Find(bson.M{"a": 1}).One(&result) -// -// In case the resulting document includes a field named $err or errmsg, which -// are standard ways for MongoDB to return query errors, the returned err will -// be set to a *QueryError value including the Err message and the Code.  In -// those cases, the result argument is still unmarshalled into with the -// received document so that any other custom values may be obtained if -// desired. -// -func (q *Query) One(result interface{}) (err error) { -	q.m.Lock() -	session := q.session -	op := q.op // Copy. -	q.m.Unlock() - -	socket, err := session.acquireSocket(true) -	if err != nil { -		return err -	} -	defer socket.Release() - -	op.limit = -1 - -	session.prepareQuery(&op) - -	expectFindReply := prepareFindOp(socket, &op, 1) - -	data, err := socket.SimpleQuery(&op) -	if err != nil { -		return err -	} -	if data == nil { -		return ErrNotFound -	} -	if expectFindReply { -		var findReply struct { -			Ok     bool -			Code   int -			Errmsg string -			Cursor cursorData -		} -		err = bson.Unmarshal(data, &findReply) -		if err != nil { -			return err -		} -		if !findReply.Ok && findReply.Errmsg != "" { -			return &QueryError{Code: findReply.Code, Message: findReply.Errmsg} -		} -		if len(findReply.Cursor.FirstBatch) == 0 { -			return ErrNotFound -		} -		data = findReply.Cursor.FirstBatch[0].Data -	} -	if result != nil { -		err = bson.Unmarshal(data, result) -		if err == nil { -			debugf("Query %p document unmarshaled: %#v", q, result) -		} else { -			debugf("Query %p document unmarshaling failed: %#v", q, err) -			return err -		} -	} -	return checkQueryError(op.collection, data) -} - -// prepareFindOp translates op from being an old-style wire protocol query into -// a new-style find command if that's supported by the MongoDB server (3.2+). -// It returns whether to expect a find command result or not. Note op may be -// translated into an explain command, in which case the function returns false. -func prepareFindOp(socket *mongoSocket, op *queryOp, limit int32) bool { -	if socket.ServerInfo().MaxWireVersion < 4 || op.collection == "admin.$cmd" { -		return false -	} - -	nameDot := strings.Index(op.collection, ".") -	if nameDot < 0 { -		panic("invalid query collection name: " + op.collection) -	} - -	find := findCmd{ -		Collection:  op.collection[nameDot+1:], -		Filter:      op.query, -		Projection:  op.selector, -		Sort:        op.options.OrderBy, -		Skip:        op.skip, -		Limit:       limit, -		MaxTimeMS:   op.options.MaxTimeMS, -		MaxScan:     op.options.MaxScan, -		Hint:        op.options.Hint, -		Comment:     op.options.Comment, -		Snapshot:    op.options.Snapshot, -		OplogReplay: op.flags&flagLogReplay != 0, -	} -	if op.limit < 0 { -		find.BatchSize = -op.limit -		find.SingleBatch = true -	} else { -		find.BatchSize = op.limit -	} - -	explain := op.options.Explain - -	op.collection = op.collection[:nameDot] + ".$cmd" -	op.query = &find -	op.skip = 0 -	op.limit = -1 -	op.options = queryWrapper{} -	op.hasOptions = false - -	if explain { -		op.query = bson.D{{"explain", op.query}} -		return false -	} -	return true -} - -type cursorData struct { -	FirstBatch []bson.Raw "firstBatch" -	NextBatch  []bson.Raw "nextBatch" -	NS         string -	Id         int64 -} - -// findCmd holds the command used for performing queries on MongoDB 3.2+. -// -// Relevant documentation: -// -//     https://docs.mongodb.org/master/reference/command/find/#dbcmd.find -// -type findCmd struct { -	Collection          string      `bson:"find"` -	Filter              interface{} `bson:"filter,omitempty"` -	Sort                interface{} `bson:"sort,omitempty"` -	Projection          interface{} `bson:"projection,omitempty"` -	Hint                interface{} `bson:"hint,omitempty"` -	Skip                interface{} `bson:"skip,omitempty"` -	Limit               int32       `bson:"limit,omitempty"` -	BatchSize           int32       `bson:"batchSize,omitempty"` -	SingleBatch         bool        `bson:"singleBatch,omitempty"` -	Comment             string      `bson:"comment,omitempty"` -	MaxScan             int         `bson:"maxScan,omitempty"` -	MaxTimeMS           int         `bson:"maxTimeMS,omitempty"` -	ReadConcern         interface{} `bson:"readConcern,omitempty"` -	Max                 interface{} `bson:"max,omitempty"` -	Min                 interface{} `bson:"min,omitempty"` -	ReturnKey           bool        `bson:"returnKey,omitempty"` -	ShowRecordId        bool        `bson:"showRecordId,omitempty"` -	Snapshot            bool        `bson:"snapshot,omitempty"` -	Tailable            bool        `bson:"tailable,omitempty"` -	AwaitData           bool        `bson:"awaitData,omitempty"` -	OplogReplay         bool        `bson:"oplogReplay,omitempty"` -	NoCursorTimeout     bool        `bson:"noCursorTimeout,omitempty"` -	AllowPartialResults bool        `bson:"allowPartialResults,omitempty"` -} - -// getMoreCmd holds the command used for requesting more query results on MongoDB 3.2+. -// -// Relevant documentation: -// -//     https://docs.mongodb.org/master/reference/command/getMore/#dbcmd.getMore -// -type getMoreCmd struct { -	CursorId   int64  `bson:"getMore"` -	Collection string `bson:"collection"` -	BatchSize  int32  `bson:"batchSize,omitempty"` -	MaxTimeMS  int64  `bson:"maxTimeMS,omitempty"` -} - -// run duplicates the behavior of collection.Find(query).One(&result) -// as performed by Database.Run, specializing the logic for running -// database commands on a given socket. -func (db *Database) run(socket *mongoSocket, cmd, result interface{}) (err error) { -	// Database.Run: -	if name, ok := cmd.(string); ok { -		cmd = bson.D{{name, 1}} -	} - -	// Collection.Find: -	session := db.Session -	session.m.RLock() -	op := session.queryConfig.op // Copy. -	session.m.RUnlock() -	op.query = cmd -	op.collection = db.Name + ".$cmd" - -	// Query.One: -	session.prepareQuery(&op) -	op.limit = -1 - -	data, err := socket.SimpleQuery(&op) -	if err != nil { -		return err -	} -	if data == nil { -		return ErrNotFound -	} -	if result != nil { -		err = bson.Unmarshal(data, result) -		if err != nil { -			debugf("Run command unmarshaling failed: %#v", op, err) -			return err -		} -		if globalDebug && globalLogger != nil { -			var res bson.M -			bson.Unmarshal(data, &res) -			debugf("Run command unmarshaled: %#v, result: %#v", op, res) -		} -	} -	return checkQueryError(op.collection, data) -} - -// The DBRef type implements support for the database reference MongoDB -// convention as supported by multiple drivers.  This convention enables -// cross-referencing documents between collections and databases using -// a structure which includes a collection name, a document id, and -// optionally a database name. -// -// See the FindRef methods on Session and on Database. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Database+References -// -type DBRef struct { -	Collection string      `bson:"$ref"` -	Id         interface{} `bson:"$id"` -	Database   string      `bson:"$db,omitempty"` -} - -// NOTE: Order of fields for DBRef above does matter, per documentation. - -// FindRef returns a query that looks for the document in the provided -// reference. If the reference includes the DB field, the document will -// be retrieved from the respective database. -// -// See also the DBRef type and the FindRef method on Session. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Database+References -// -func (db *Database) FindRef(ref *DBRef) *Query { -	var c *Collection -	if ref.Database == "" { -		c = db.C(ref.Collection) -	} else { -		c = db.Session.DB(ref.Database).C(ref.Collection) -	} -	return c.FindId(ref.Id) -} - -// FindRef returns a query that looks for the document in the provided -// reference. For a DBRef to be resolved correctly at the session level -// it must necessarily have the optional DB field defined. -// -// See also the DBRef type and the FindRef method on Database. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Database+References -// -func (s *Session) FindRef(ref *DBRef) *Query { -	if ref.Database == "" { -		panic(errors.New(fmt.Sprintf("Can't resolve database for %#v", ref))) -	} -	c := s.DB(ref.Database).C(ref.Collection) -	return c.FindId(ref.Id) -} - -// CollectionNames returns the collection names present in the db database. -func (db *Database) CollectionNames() (names []string, err error) { -	// Clone session and set it to Monotonic mode so that the server -	// used for the query may be safely obtained afterwards, if -	// necessary for iteration when a cursor is received. -	cloned := db.Session.nonEventual() -	defer cloned.Close() - -	batchSize := int(cloned.queryConfig.op.limit) - -	// Try with a command. -	var result struct { -		Collections []bson.Raw -		Cursor      cursorData -	} -	err = db.With(cloned).Run(bson.D{{"listCollections", 1}, {"cursor", bson.D{{"batchSize", batchSize}}}}, &result) -	if err == nil { -		firstBatch := result.Collections -		if firstBatch == nil { -			firstBatch = result.Cursor.FirstBatch -		} -		var iter *Iter -		ns := strings.SplitN(result.Cursor.NS, ".", 2) -		if len(ns) < 2 { -			iter = db.With(cloned).C("").NewIter(nil, firstBatch, result.Cursor.Id, nil) -		} else { -			iter = cloned.DB(ns[0]).C(ns[1]).NewIter(nil, firstBatch, result.Cursor.Id, nil) -		} -		var coll struct{ Name string } -		for iter.Next(&coll) { -			names = append(names, coll.Name) -		} -		if err := iter.Close(); err != nil { -			return nil, err -		} -		sort.Strings(names) -		return names, err -	} -	if err != nil && !isNoCmd(err) { -		return nil, err -	} - -	// Command not yet supported. Query the database instead. -	nameIndex := len(db.Name) + 1 -	iter := db.C("system.namespaces").Find(nil).Iter() -	var coll struct{ Name string } -	for iter.Next(&coll) { -		if strings.Index(coll.Name, "$") < 0 || strings.Index(coll.Name, ".oplog.$") >= 0 { -			names = append(names, coll.Name[nameIndex:]) -		} -	} -	if err := iter.Close(); err != nil { -		return nil, err -	} -	sort.Strings(names) -	return names, nil -} - -type dbNames struct { -	Databases []struct { -		Name  string -		Empty bool -	} -} - -// DatabaseNames returns the names of non-empty databases present in the cluster. -func (s *Session) DatabaseNames() (names []string, err error) { -	var result dbNames -	err = s.Run("listDatabases", &result) -	if err != nil { -		return nil, err -	} -	for _, db := range result.Databases { -		if !db.Empty { -			names = append(names, db.Name) -		} -	} -	sort.Strings(names) -	return names, nil -} - -// Iter executes the query and returns an iterator capable of going over all -// the results. Results will be returned in batches of configurable -// size (see the Batch method) and more documents will be requested when a -// configurable number of documents is iterated over (see the Prefetch method). -func (q *Query) Iter() *Iter { -	q.m.Lock() -	session := q.session -	op := q.op -	prefetch := q.prefetch -	limit := q.limit -	q.m.Unlock() - -	iter := &Iter{ -		session:  session, -		prefetch: prefetch, -		limit:    limit, -		timeout:  -1, -	} -	iter.gotReply.L = &iter.m -	iter.op.collection = op.collection -	iter.op.limit = op.limit -	iter.op.replyFunc = iter.replyFunc() -	iter.docsToReceive++ - -	socket, err := session.acquireSocket(true) -	if err != nil { -		iter.err = err -		return iter -	} -	defer socket.Release() - -	session.prepareQuery(&op) -	op.replyFunc = iter.op.replyFunc - -	if prepareFindOp(socket, &op, limit) { -		iter.findCmd = true -	} - -	iter.server = socket.Server() -	err = socket.Query(&op) -	if err != nil { -		// Must lock as the query is already out and it may call replyFunc. -		iter.m.Lock() -		iter.err = err -		iter.m.Unlock() -	} - -	return iter -} - -// Tail returns a tailable iterator. Unlike a normal iterator, a -// tailable iterator may wait for new values to be inserted in the -// collection once the end of the current result set is reached, -// A tailable iterator may only be used with capped collections. -// -// The timeout parameter indicates how long Next will block waiting -// for a result before timing out.  If set to -1, Next will not -// timeout, and will continue waiting for a result for as long as -// the cursor is valid and the session is not closed. If set to 0, -// Next times out as soon as it reaches the end of the result set. -// Otherwise, Next will wait for at least the given number of -// seconds for a new document to be available before timing out. -// -// On timeouts, Next will unblock and return false, and the Timeout -// method will return true if called. In these cases, Next may still -// be called again on the same iterator to check if a new value is -// available at the current cursor position, and again it will block -// according to the specified timeoutSecs. If the cursor becomes -// invalid, though, both Next and Timeout will return false and -// the query must be restarted. -// -// The following example demonstrates timeout handling and query -// restarting: -// -//    iter := collection.Find(nil).Sort("$natural").Tail(5 * time.Second) -//    for { -//         for iter.Next(&result) { -//             fmt.Println(result.Id) -//             lastId = result.Id -//         } -//         if iter.Err() != nil { -//             return iter.Close() -//         } -//         if iter.Timeout() { -//             continue -//         } -//         query := collection.Find(bson.M{"_id": bson.M{"$gt": lastId}}) -//         iter = query.Sort("$natural").Tail(5 * time.Second) -//    } -//    iter.Close() -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Tailable+Cursors -//     http://www.mongodb.org/display/DOCS/Capped+Collections -//     http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order -// -func (q *Query) Tail(timeout time.Duration) *Iter { -	q.m.Lock() -	session := q.session -	op := q.op -	prefetch := q.prefetch -	q.m.Unlock() - -	iter := &Iter{session: session, prefetch: prefetch} -	iter.gotReply.L = &iter.m -	iter.timeout = timeout -	iter.op.collection = op.collection -	iter.op.limit = op.limit -	iter.op.replyFunc = iter.replyFunc() -	iter.docsToReceive++ -	session.prepareQuery(&op) -	op.replyFunc = iter.op.replyFunc -	op.flags |= flagTailable | flagAwaitData - -	socket, err := session.acquireSocket(true) -	if err != nil { -		iter.err = err -	} else { -		iter.server = socket.Server() -		err = socket.Query(&op) -		if err != nil { -			// Must lock as the query is already out and it may call replyFunc. -			iter.m.Lock() -			iter.err = err -			iter.m.Unlock() -		} -		socket.Release() -	} -	return iter -} - -func (s *Session) prepareQuery(op *queryOp) { -	s.m.RLock() -	op.mode = s.consistency -	if s.slaveOk { -		op.flags |= flagSlaveOk -	} -	s.m.RUnlock() -	return -} - -// Err returns nil if no errors happened during iteration, or the actual -// error otherwise. -// -// In case a resulting document included a field named $err or errmsg, which are -// standard ways for MongoDB to report an improper query, the returned value has -// a *QueryError type, and includes the Err message and the Code. -func (iter *Iter) Err() error { -	iter.m.Lock() -	err := iter.err -	iter.m.Unlock() -	if err == ErrNotFound { -		return nil -	} -	return err -} - -// Close kills the server cursor used by the iterator, if any, and returns -// nil if no errors happened during iteration, or the actual error otherwise. -// -// Server cursors are automatically closed at the end of an iteration, which -// means close will do nothing unless the iteration was interrupted before -// the server finished sending results to the driver. If Close is not called -// in such a situation, the cursor will remain available at the server until -// the default cursor timeout period is reached. No further problems arise. -// -// Close is idempotent. That means it can be called repeatedly and will -// return the same result every time. -// -// In case a resulting document included a field named $err or errmsg, which are -// standard ways for MongoDB to report an improper query, the returned value has -// a *QueryError type. -func (iter *Iter) Close() error { -	iter.m.Lock() -	cursorId := iter.op.cursorId -	iter.op.cursorId = 0 -	err := iter.err -	iter.m.Unlock() -	if cursorId == 0 { -		if err == ErrNotFound { -			return nil -		} -		return err -	} -	socket, err := iter.acquireSocket() -	if err == nil { -		// TODO Batch kills. -		err = socket.Query(&killCursorsOp{[]int64{cursorId}}) -		socket.Release() -	} - -	iter.m.Lock() -	if err != nil && (iter.err == nil || iter.err == ErrNotFound) { -		iter.err = err -	} else if iter.err != ErrNotFound { -		err = iter.err -	} -	iter.m.Unlock() -	return err -} - -// Done returns true only if a follow up Next call is guaranteed -// to return false. -// -// For an iterator created with Tail, Done may return false for -// an iterator that has no more data. Otherwise it's guaranteed -// to return false only if there is data or an error happened. -// -// Done may block waiting for a pending query to verify whether -// more data is actually available or not. -func (iter *Iter) Done() bool { -	iter.m.Lock() -	defer iter.m.Unlock() - -	for { -		if iter.docData.Len() > 0 { -			return false -		} -		if iter.docsToReceive > 1 { -			return true -		} -		if iter.docsToReceive > 0 { -			iter.gotReply.Wait() -			continue -		} -		return iter.op.cursorId == 0 -	} -} - -// Timeout returns true if Next returned false due to a timeout of -// a tailable cursor. In those cases, Next may be called again to continue -// the iteration at the previous cursor position. -func (iter *Iter) Timeout() bool { -	iter.m.Lock() -	result := iter.timedout -	iter.m.Unlock() -	return result -} - -// Next retrieves the next document from the result set, blocking if necessary. -// This method will also automatically retrieve another batch of documents from -// the server when the current one is exhausted, or before that in background -// if pre-fetching is enabled (see the Query.Prefetch and Session.SetPrefetch -// methods). -// -// Next returns true if a document was successfully unmarshalled onto result, -// and false at the end of the result set or if an error happened. -// When Next returns false, the Err method should be called to verify if -// there was an error during iteration. -// -// For example: -// -//    iter := collection.Find(nil).Iter() -//    for iter.Next(&result) { -//        fmt.Printf("Result: %v\n", result.Id) -//    } -//    if err := iter.Close(); err != nil { -//        return err -//    } -// -func (iter *Iter) Next(result interface{}) bool { -	iter.m.Lock() -	iter.timedout = false -	timeout := time.Time{} -	for iter.err == nil && iter.docData.Len() == 0 && (iter.docsToReceive > 0 || iter.op.cursorId != 0) { -		if iter.docsToReceive == 0 { -			if iter.timeout >= 0 { -				if timeout.IsZero() { -					timeout = time.Now().Add(iter.timeout) -				} -				if time.Now().After(timeout) { -					iter.timedout = true -					iter.m.Unlock() -					return false -				} -			} -			iter.getMore() -			if iter.err != nil { -				break -			} -		} -		iter.gotReply.Wait() -	} - -	// Exhaust available data before reporting any errors. -	if docData, ok := iter.docData.Pop().([]byte); ok { -		close := false -		if iter.limit > 0 { -			iter.limit-- -			if iter.limit == 0 { -				if iter.docData.Len() > 0 { -					iter.m.Unlock() -					panic(fmt.Errorf("data remains after limit exhausted: %d", iter.docData.Len())) -				} -				iter.err = ErrNotFound -				close = true -			} -		} -		if iter.op.cursorId != 0 && iter.err == nil { -			iter.docsBeforeMore-- -			if iter.docsBeforeMore == -1 { -				iter.getMore() -			} -		} -		iter.m.Unlock() - -		if close { -			iter.Close() -		} -		err := bson.Unmarshal(docData, result) -		if err != nil { -			debugf("Iter %p document unmarshaling failed: %#v", iter, err) -			iter.m.Lock() -			if iter.err == nil { -				iter.err = err -			} -			iter.m.Unlock() -			return false -		} -		debugf("Iter %p document unmarshaled: %#v", iter, result) -		// XXX Only have to check first document for a query error? -		err = checkQueryError(iter.op.collection, docData) -		if err != nil { -			iter.m.Lock() -			if iter.err == nil { -				iter.err = err -			} -			iter.m.Unlock() -			return false -		} -		return true -	} else if iter.err != nil { -		debugf("Iter %p returning false: %s", iter, iter.err) -		iter.m.Unlock() -		return false -	} else if iter.op.cursorId == 0 { -		iter.err = ErrNotFound -		debugf("Iter %p exhausted with cursor=0", iter) -		iter.m.Unlock() -		return false -	} - -	panic("unreachable") -} - -// All retrieves all documents from the result set into the provided slice -// and closes the iterator. -// -// The result argument must necessarily be the address for a slice. The slice -// may be nil or previously allocated. -// -// WARNING: Obviously, All must not be used with result sets that may be -// potentially large, since it may consume all memory until the system -// crashes. Consider building the query with a Limit clause to ensure the -// result size is bounded. -// -// For instance: -// -//    var result []struct{ Value int } -//    iter := collection.Find(nil).Limit(100).Iter() -//    err := iter.All(&result) -//    if err != nil { -//        return err -//    } -// -func (iter *Iter) All(result interface{}) error { -	resultv := reflect.ValueOf(result) -	if resultv.Kind() != reflect.Ptr || resultv.Elem().Kind() != reflect.Slice { -		panic("result argument must be a slice address") -	} -	slicev := resultv.Elem() -	slicev = slicev.Slice(0, slicev.Cap()) -	elemt := slicev.Type().Elem() -	i := 0 -	for { -		if slicev.Len() == i { -			elemp := reflect.New(elemt) -			if !iter.Next(elemp.Interface()) { -				break -			} -			slicev = reflect.Append(slicev, elemp.Elem()) -			slicev = slicev.Slice(0, slicev.Cap()) -		} else { -			if !iter.Next(slicev.Index(i).Addr().Interface()) { -				break -			} -		} -		i++ -	} -	resultv.Elem().Set(slicev.Slice(0, i)) -	return iter.Close() -} - -// All works like Iter.All. -func (q *Query) All(result interface{}) error { -	return q.Iter().All(result) -} - -// The For method is obsolete and will be removed in a future release. -// See Iter as an elegant replacement. -func (q *Query) For(result interface{}, f func() error) error { -	return q.Iter().For(result, f) -} - -// The For method is obsolete and will be removed in a future release. -// See Iter as an elegant replacement. -func (iter *Iter) For(result interface{}, f func() error) (err error) { -	valid := false -	v := reflect.ValueOf(result) -	if v.Kind() == reflect.Ptr { -		v = v.Elem() -		switch v.Kind() { -		case reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: -			valid = v.IsNil() -		} -	} -	if !valid { -		panic("For needs a pointer to nil reference value.  See the documentation.") -	} -	zero := reflect.Zero(v.Type()) -	for { -		v.Set(zero) -		if !iter.Next(result) { -			break -		} -		err = f() -		if err != nil { -			return err -		} -	} -	return iter.Err() -} - -// acquireSocket acquires a socket from the same server that the iterator -// cursor was obtained from. -// -// WARNING: This method must not be called with iter.m locked. Acquiring the -// socket depends on the cluster sync loop, and the cluster sync loop might -// attempt actions which cause replyFunc to be called, inducing a deadlock. -func (iter *Iter) acquireSocket() (*mongoSocket, error) { -	socket, err := iter.session.acquireSocket(true) -	if err != nil { -		return nil, err -	} -	if socket.Server() != iter.server { -		// Socket server changed during iteration. This may happen -		// with Eventual sessions, if a Refresh is done, or if a -		// monotonic session gets a write and shifts from secondary -		// to primary. Our cursor is in a specific server, though. -		iter.session.m.Lock() -		sockTimeout := iter.session.sockTimeout -		iter.session.m.Unlock() -		socket.Release() -		socket, _, err = iter.server.AcquireSocket(0, sockTimeout) -		if err != nil { -			return nil, err -		} -		err := iter.session.socketLogin(socket) -		if err != nil { -			socket.Release() -			return nil, err -		} -	} -	return socket, nil -} - -func (iter *Iter) getMore() { -	// Increment now so that unlocking the iterator won't cause a -	// different goroutine to get here as well. -	iter.docsToReceive++ -	iter.m.Unlock() -	socket, err := iter.acquireSocket() -	iter.m.Lock() -	if err != nil { -		iter.err = err -		return -	} -	defer socket.Release() - -	debugf("Iter %p requesting more documents", iter) -	if iter.limit > 0 { -		// The -1 below accounts for the fact docsToReceive was incremented above. -		limit := iter.limit - int32(iter.docsToReceive-1) - int32(iter.docData.Len()) -		if limit < iter.op.limit { -			iter.op.limit = limit -		} -	} -	var op interface{} -	if iter.findCmd { -		op = iter.getMoreCmd() -	} else { -		op = &iter.op -	} -	if err := socket.Query(op); err != nil { -		iter.docsToReceive-- -		iter.err = err -	} -} - -func (iter *Iter) getMoreCmd() *queryOp { -	// TODO: Define the query statically in the Iter type, next to getMoreOp. -	nameDot := strings.Index(iter.op.collection, ".") -	if nameDot < 0 { -		panic("invalid query collection name: " + iter.op.collection) -	} - -	getMore := getMoreCmd{ -		CursorId:   iter.op.cursorId, -		Collection: iter.op.collection[nameDot+1:], -		BatchSize:  iter.op.limit, -	} - -	var op queryOp -	op.collection = iter.op.collection[:nameDot] + ".$cmd" -	op.query = &getMore -	op.limit = -1 -	op.replyFunc = iter.op.replyFunc -	return &op -} - -type countCmd struct { -	Count string -	Query interface{} -	Limit int32 ",omitempty" -	Skip  int32 ",omitempty" -} - -// Count returns the total number of documents in the result set. -func (q *Query) Count() (n int, err error) { -	q.m.Lock() -	session := q.session -	op := q.op -	limit := q.limit -	q.m.Unlock() - -	c := strings.Index(op.collection, ".") -	if c < 0 { -		return 0, errors.New("Bad collection name: " + op.collection) -	} - -	dbname := op.collection[:c] -	cname := op.collection[c+1:] -	query := op.query -	if query == nil { -		query = bson.D{} -	} -	result := struct{ N int }{} -	err = session.DB(dbname).Run(countCmd{cname, query, limit, op.skip}, &result) -	return result.N, err -} - -// Count returns the total number of documents in the collection. -func (c *Collection) Count() (n int, err error) { -	return c.Find(nil).Count() -} - -type distinctCmd struct { -	Collection string "distinct" -	Key        string -	Query      interface{} ",omitempty" -} - -// Distinct unmarshals into result the list of distinct values for the given key. -// -// For example: -// -//     var result []int -//     err := collection.Find(bson.M{"gender": "F"}).Distinct("age", &result) -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/Aggregation -// -func (q *Query) Distinct(key string, result interface{}) error { -	q.m.Lock() -	session := q.session -	op := q.op // Copy. -	q.m.Unlock() - -	c := strings.Index(op.collection, ".") -	if c < 0 { -		return errors.New("Bad collection name: " + op.collection) -	} - -	dbname := op.collection[:c] -	cname := op.collection[c+1:] - -	var doc struct{ Values bson.Raw } -	err := session.DB(dbname).Run(distinctCmd{cname, key, op.query}, &doc) -	if err != nil { -		return err -	} -	return doc.Values.Unmarshal(result) -} - -type mapReduceCmd struct { -	Collection string "mapreduce" -	Map        string ",omitempty" -	Reduce     string ",omitempty" -	Finalize   string ",omitempty" -	Limit      int32  ",omitempty" -	Out        interface{} -	Query      interface{} ",omitempty" -	Sort       interface{} ",omitempty" -	Scope      interface{} ",omitempty" -	Verbose    bool        ",omitempty" -} - -type mapReduceResult struct { -	Results    bson.Raw -	Result     bson.Raw -	TimeMillis int64 "timeMillis" -	Counts     struct{ Input, Emit, Output int } -	Ok         bool -	Err        string -	Timing     *MapReduceTime -} - -type MapReduce struct { -	Map      string      // Map Javascript function code (required) -	Reduce   string      // Reduce Javascript function code (required) -	Finalize string      // Finalize Javascript function code (optional) -	Out      interface{} // Output collection name or document. If nil, results are inlined into the result parameter. -	Scope    interface{} // Optional global scope for Javascript functions -	Verbose  bool -} - -type MapReduceInfo struct { -	InputCount  int            // Number of documents mapped -	EmitCount   int            // Number of times reduce called emit -	OutputCount int            // Number of documents in resulting collection -	Database    string         // Output database, if results are not inlined -	Collection  string         // Output collection, if results are not inlined -	Time        int64          // Time to run the job, in nanoseconds -	VerboseTime *MapReduceTime // Only defined if Verbose was true -} - -type MapReduceTime struct { -	Total    int64 // Total time, in nanoseconds -	Map      int64 "mapTime"  // Time within map function, in nanoseconds -	EmitLoop int64 "emitLoop" // Time within the emit/map loop, in nanoseconds -} - -// MapReduce executes a map/reduce job for documents covered by the query. -// That kind of job is suitable for very flexible bulk aggregation of data -// performed at the server side via Javascript functions. -// -// Results from the job may be returned as a result of the query itself -// through the result parameter in case they'll certainly fit in memory -// and in a single document.  If there's the possibility that the amount -// of data might be too large, results must be stored back in an alternative -// collection or even a separate database, by setting the Out field of the -// provided MapReduce job.  In that case, provide nil as the result parameter. -// -// These are some of the ways to set Out: -// -//     nil -//         Inline results into the result parameter. -// -//     bson.M{"replace": "mycollection"} -//         The output will be inserted into a collection which replaces any -//         existing collection with the same name. -// -//     bson.M{"merge": "mycollection"} -//         This option will merge new data into the old output collection. In -//         other words, if the same key exists in both the result set and the -//         old collection, the new key will overwrite the old one. -// -//     bson.M{"reduce": "mycollection"} -//         If documents exist for a given key in the result set and in the old -//         collection, then a reduce operation (using the specified reduce -//         function) will be performed on the two values and the result will be -//         written to the output collection. If a finalize function was -//         provided, this will be run after the reduce as well. -// -//     bson.M{...., "db": "mydb"} -//         Any of the above options can have the "db" key included for doing -//         the respective action in a separate database. -// -// The following is a trivial example which will count the number of -// occurrences of a field named n on each document in a collection, and -// will return results inline: -// -//     job := &mgo.MapReduce{ -//             Map:      "function() { emit(this.n, 1) }", -//             Reduce:   "function(key, values) { return Array.sum(values) }", -//     } -//     var result []struct { Id int "_id"; Value int } -//     _, err := collection.Find(nil).MapReduce(job, &result) -//     if err != nil { -//         return err -//     } -//     for _, item := range result { -//         fmt.Println(item.Value) -//     } -// -// This function is compatible with MongoDB 1.7.4+. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/MapReduce -// -func (q *Query) MapReduce(job *MapReduce, result interface{}) (info *MapReduceInfo, err error) { -	q.m.Lock() -	session := q.session -	op := q.op // Copy. -	limit := q.limit -	q.m.Unlock() - -	c := strings.Index(op.collection, ".") -	if c < 0 { -		return nil, errors.New("Bad collection name: " + op.collection) -	} - -	dbname := op.collection[:c] -	cname := op.collection[c+1:] - -	cmd := mapReduceCmd{ -		Collection: cname, -		Map:        job.Map, -		Reduce:     job.Reduce, -		Finalize:   job.Finalize, -		Out:        fixMROut(job.Out), -		Scope:      job.Scope, -		Verbose:    job.Verbose, -		Query:      op.query, -		Sort:       op.options.OrderBy, -		Limit:      limit, -	} - -	if cmd.Out == nil { -		cmd.Out = bson.D{{"inline", 1}} -	} - -	var doc mapReduceResult -	err = session.DB(dbname).Run(&cmd, &doc) -	if err != nil { -		return nil, err -	} -	if doc.Err != "" { -		return nil, errors.New(doc.Err) -	} - -	info = &MapReduceInfo{ -		InputCount:  doc.Counts.Input, -		EmitCount:   doc.Counts.Emit, -		OutputCount: doc.Counts.Output, -		Time:        doc.TimeMillis * 1e6, -	} - -	if doc.Result.Kind == 0x02 { -		err = doc.Result.Unmarshal(&info.Collection) -		info.Database = dbname -	} else if doc.Result.Kind == 0x03 { -		var v struct{ Collection, Db string } -		err = doc.Result.Unmarshal(&v) -		info.Collection = v.Collection -		info.Database = v.Db -	} - -	if doc.Timing != nil { -		info.VerboseTime = doc.Timing -		info.VerboseTime.Total *= 1e6 -		info.VerboseTime.Map *= 1e6 -		info.VerboseTime.EmitLoop *= 1e6 -	} - -	if err != nil { -		return nil, err -	} -	if result != nil { -		return info, doc.Results.Unmarshal(result) -	} -	return info, nil -} - -// The "out" option in the MapReduce command must be ordered. This was -// found after the implementation was accepting maps for a long time, -// so rather than breaking the API, we'll fix the order if necessary. -// Details about the order requirement may be seen in MongoDB's code: -// -//     http://goo.gl/L8jwJX -// -func fixMROut(out interface{}) interface{} { -	outv := reflect.ValueOf(out) -	if outv.Kind() != reflect.Map || outv.Type().Key() != reflect.TypeOf("") { -		return out -	} -	outs := make(bson.D, outv.Len()) - -	outTypeIndex := -1 -	for i, k := range outv.MapKeys() { -		ks := k.String() -		outs[i].Name = ks -		outs[i].Value = outv.MapIndex(k).Interface() -		switch ks { -		case "normal", "replace", "merge", "reduce", "inline": -			outTypeIndex = i -		} -	} -	if outTypeIndex > 0 { -		outs[0], outs[outTypeIndex] = outs[outTypeIndex], outs[0] -	} -	return outs -} - -// Change holds fields for running a findAndModify MongoDB command via -// the Query.Apply method. -type Change struct { -	Update    interface{} // The update document -	Upsert    bool        // Whether to insert in case the document isn't found -	Remove    bool        // Whether to remove the document found rather than updating -	ReturnNew bool        // Should the modified document be returned rather than the old one -} - -type findModifyCmd struct { -	Collection                  string      "findAndModify" -	Query, Update, Sort, Fields interface{} ",omitempty" -	Upsert, Remove, New         bool        ",omitempty" -} - -type valueResult struct { -	Value     bson.Raw -	LastError LastError "lastErrorObject" -} - -// Apply runs the findAndModify MongoDB command, which allows updating, upserting -// or removing a document matching a query and atomically returning either the old -// version (the default) or the new version of the document (when ReturnNew is true). -// If no objects are found Apply returns ErrNotFound. -// -// The Sort and Select query methods affect the result of Apply.  In case -// multiple documents match the query, Sort enables selecting which document to -// act upon by ordering it first.  Select enables retrieving only a selection -// of fields of the new or old document. -// -// This simple example increments a counter and prints its new value: -// -//     change := mgo.Change{ -//             Update: bson.M{"$inc": bson.M{"n": 1}}, -//             ReturnNew: true, -//     } -//     info, err = col.Find(M{"_id": id}).Apply(change, &doc) -//     fmt.Println(doc.N) -// -// This method depends on MongoDB >= 2.0 to work properly. -// -// Relevant documentation: -// -//     http://www.mongodb.org/display/DOCS/findAndModify+Command -//     http://www.mongodb.org/display/DOCS/Updating -//     http://www.mongodb.org/display/DOCS/Atomic+Operations -// -func (q *Query) Apply(change Change, result interface{}) (info *ChangeInfo, err error) { -	q.m.Lock() -	session := q.session -	op := q.op // Copy. -	q.m.Unlock() - -	c := strings.Index(op.collection, ".") -	if c < 0 { -		return nil, errors.New("bad collection name: " + op.collection) -	} - -	dbname := op.collection[:c] -	cname := op.collection[c+1:] - -	cmd := findModifyCmd{ -		Collection: cname, -		Update:     change.Update, -		Upsert:     change.Upsert, -		Remove:     change.Remove, -		New:        change.ReturnNew, -		Query:      op.query, -		Sort:       op.options.OrderBy, -		Fields:     op.selector, -	} - -	session = session.Clone() -	defer session.Close() -	session.SetMode(Strong, false) - -	var doc valueResult -	for i := 0; i < maxUpsertRetries; i++ { -		err = session.DB(dbname).Run(&cmd, &doc) -		if err == nil { -			break -		} -		if change.Upsert && IsDup(err) && i+1 < maxUpsertRetries { -			// Retry duplicate key errors on upserts. -			// https://docs.mongodb.com/v3.2/reference/method/db.collection.update/#use-unique-indexes -			continue -		} -		if qerr, ok := err.(*QueryError); ok && qerr.Message == "No matching object found" { -			return nil, ErrNotFound -		} -		return nil, err -	} -	if doc.LastError.N == 0 { -		return nil, ErrNotFound -	} -	if doc.Value.Kind != 0x0A && result != nil { -		err = doc.Value.Unmarshal(result) -		if err != nil { -			return nil, err -		} -	} -	info = &ChangeInfo{} -	lerr := &doc.LastError -	if lerr.UpdatedExisting { -		info.Updated = lerr.N -		info.Matched = lerr.N -	} else if change.Remove { -		info.Removed = lerr.N -		info.Matched = lerr.N -	} else if change.Upsert { -		info.UpsertedId = lerr.UpsertedId -	} -	return info, nil -} - -// The BuildInfo type encapsulates details about the running MongoDB server. -// -// Note that the VersionArray field was introduced in MongoDB 2.0+, but it is -// internally assembled from the Version information for previous versions. -// In both cases, VersionArray is guaranteed to have at least 4 entries. -type BuildInfo struct { -	Version        string -	VersionArray   []int  `bson:"versionArray"` // On MongoDB 2.0+; assembled from Version otherwise -	GitVersion     string `bson:"gitVersion"` -	OpenSSLVersion string `bson:"OpenSSLVersion"` -	SysInfo        string `bson:"sysInfo"` // Deprecated and empty on MongoDB 3.2+. -	Bits           int -	Debug          bool -	MaxObjectSize  int `bson:"maxBsonObjectSize"` -} - -// VersionAtLeast returns whether the BuildInfo version is greater than or -// equal to the provided version number. If more than one number is -// provided, numbers will be considered as major, minor, and so on. -func (bi *BuildInfo) VersionAtLeast(version ...int) bool { -	for i, vi := range version { -		if i == len(bi.VersionArray) { -			return false -		} -		if bivi := bi.VersionArray[i]; bivi != vi { -			return bivi >= vi -		} -	} -	return true -} - -// BuildInfo retrieves the version and other details about the -// running MongoDB server. -func (s *Session) BuildInfo() (info BuildInfo, err error) { -	err = s.Run(bson.D{{"buildInfo", "1"}}, &info) -	if len(info.VersionArray) == 0 { -		for _, a := range strings.Split(info.Version, ".") { -			i, err := strconv.Atoi(a) -			if err != nil { -				break -			} -			info.VersionArray = append(info.VersionArray, i) -		} -	} -	for len(info.VersionArray) < 4 { -		info.VersionArray = append(info.VersionArray, 0) -	} -	if i := strings.IndexByte(info.GitVersion, ' '); i >= 0 { -		// Strip off the " modules: enterprise" suffix. This is a _git version_. -		// That information may be moved to another field if people need it. -		info.GitVersion = info.GitVersion[:i] -	} -	if info.SysInfo == "deprecated" { -		info.SysInfo = "" -	} -	return -} - -// --------------------------------------------------------------------------- -// Internal session handling helpers. - -func (s *Session) acquireSocket(slaveOk bool) (*mongoSocket, error) { - -	// Read-only lock to check for previously reserved socket. -	s.m.RLock() -	// If there is a slave socket reserved and its use is acceptable, take it as long -	// as there isn't a master socket which would be preferred by the read preference mode. -	if s.slaveSocket != nil && s.slaveOk && slaveOk && (s.masterSocket == nil || s.consistency != PrimaryPreferred && s.consistency != Monotonic) { -		socket := s.slaveSocket -		socket.Acquire() -		s.m.RUnlock() -		return socket, nil -	} -	if s.masterSocket != nil { -		socket := s.masterSocket -		socket.Acquire() -		s.m.RUnlock() -		return socket, nil -	} -	s.m.RUnlock() - -	// No go.  We may have to request a new socket and change the session, -	// so try again but with an exclusive lock now. -	s.m.Lock() -	defer s.m.Unlock() - -	if s.slaveSocket != nil && s.slaveOk && slaveOk && (s.masterSocket == nil || s.consistency != PrimaryPreferred && s.consistency != Monotonic) { -		s.slaveSocket.Acquire() -		return s.slaveSocket, nil -	} -	if s.masterSocket != nil { -		s.masterSocket.Acquire() -		return s.masterSocket, nil -	} - -	// Still not good.  We need a new socket. -	sock, err := s.cluster().AcquireSocket(s.consistency, slaveOk && s.slaveOk, s.syncTimeout, s.sockTimeout, s.queryConfig.op.serverTags, s.poolLimit) -	if err != nil { -		return nil, err -	} - -	// Authenticate the new socket. -	if err = s.socketLogin(sock); err != nil { -		sock.Release() -		return nil, err -	} - -	// Keep track of the new socket, if necessary. -	// Note that, as a special case, if the Eventual session was -	// not refreshed (s.slaveSocket != nil), it means the developer -	// asked to preserve an existing reserved socket, so we'll -	// keep a master one around too before a Refresh happens. -	if s.consistency != Eventual || s.slaveSocket != nil { -		s.setSocket(sock) -	} - -	// Switch over a Monotonic session to the master. -	if !slaveOk && s.consistency == Monotonic { -		s.slaveOk = false -	} - -	return sock, nil -} - -// setSocket binds socket to this section. -func (s *Session) setSocket(socket *mongoSocket) { -	info := socket.Acquire() -	if info.Master { -		if s.masterSocket != nil { -			panic("setSocket(master) with existing master socket reserved") -		} -		s.masterSocket = socket -	} else { -		if s.slaveSocket != nil { -			panic("setSocket(slave) with existing slave socket reserved") -		} -		s.slaveSocket = socket -	} -} - -// unsetSocket releases any slave and/or master sockets reserved. -func (s *Session) unsetSocket() { -	if s.masterSocket != nil { -		s.masterSocket.Release() -	} -	if s.slaveSocket != nil { -		s.slaveSocket.Release() -	} -	s.masterSocket = nil -	s.slaveSocket = nil -} - -func (iter *Iter) replyFunc() replyFunc { -	return func(err error, op *replyOp, docNum int, docData []byte) { -		iter.m.Lock() -		iter.docsToReceive-- -		if err != nil { -			iter.err = err -			debugf("Iter %p received an error: %s", iter, err.Error()) -		} else if docNum == -1 { -			debugf("Iter %p received no documents (cursor=%d).", iter, op.cursorId) -			if op != nil && op.cursorId != 0 { -				// It's a tailable cursor. -				iter.op.cursorId = op.cursorId -			} else if op != nil && op.cursorId == 0 && op.flags&1 == 1 { -				// Cursor likely timed out. -				iter.err = ErrCursor -			} else { -				iter.err = ErrNotFound -			} -		} else if iter.findCmd { -			debugf("Iter %p received reply document %d/%d (cursor=%d)", iter, docNum+1, int(op.replyDocs), op.cursorId) -			var findReply struct { -				Ok     bool -				Code   int -				Errmsg string -				Cursor cursorData -			} -			if err := bson.Unmarshal(docData, &findReply); err != nil { -				iter.err = err -			} else if !findReply.Ok && findReply.Errmsg != "" { -				iter.err = &QueryError{Code: findReply.Code, Message: findReply.Errmsg} -			} else if len(findReply.Cursor.FirstBatch) == 0 && len(findReply.Cursor.NextBatch) == 0 { -				iter.err = ErrNotFound -			} else { -				batch := findReply.Cursor.FirstBatch -				if len(batch) == 0 { -					batch = findReply.Cursor.NextBatch -				} -				rdocs := len(batch) -				for _, raw := range batch { -					iter.docData.Push(raw.Data) -				} -				iter.docsToReceive = 0 -				docsToProcess := iter.docData.Len() -				if iter.limit == 0 || int32(docsToProcess) < iter.limit { -					iter.docsBeforeMore = docsToProcess - int(iter.prefetch*float64(rdocs)) -				} else { -					iter.docsBeforeMore = -1 -				} -				iter.op.cursorId = findReply.Cursor.Id -			} -		} else { -			rdocs := int(op.replyDocs) -			if docNum == 0 { -				iter.docsToReceive += rdocs - 1 -				docsToProcess := iter.docData.Len() + rdocs -				if iter.limit == 0 || int32(docsToProcess) < iter.limit { -					iter.docsBeforeMore = docsToProcess - int(iter.prefetch*float64(rdocs)) -				} else { -					iter.docsBeforeMore = -1 -				} -				iter.op.cursorId = op.cursorId -			} -			debugf("Iter %p received reply document %d/%d (cursor=%d)", iter, docNum+1, rdocs, op.cursorId) -			iter.docData.Push(docData) -		} -		iter.gotReply.Broadcast() -		iter.m.Unlock() -	} -} - -type writeCmdResult struct { -	Ok        bool -	N         int -	NModified int `bson:"nModified"` -	Upserted  []struct { -		Index int -		Id    interface{} `_id` -	} -	ConcernError writeConcernError `bson:"writeConcernError"` -	Errors       []writeCmdError   `bson:"writeErrors"` -} - -type writeConcernError struct { -	Code   int -	ErrMsg string -} - -type writeCmdError struct { -	Index  int -	Code   int -	ErrMsg string -} - -func (r *writeCmdResult) BulkErrorCases() []BulkErrorCase { -	ecases := make([]BulkErrorCase, len(r.Errors)) -	for i, err := range r.Errors { -		ecases[i] = BulkErrorCase{err.Index, &QueryError{Code: err.Code, Message: err.ErrMsg}} -	} -	return ecases -} - -// writeOp runs the given modifying operation, potentially followed up -// by a getLastError command in case the session is in safe mode.  The -// LastError result is made available in lerr, and if lerr.Err is set it -// will also be returned as err. -func (c *Collection) writeOp(op interface{}, ordered bool) (lerr *LastError, err error) { -	s := c.Database.Session -	socket, err := s.acquireSocket(c.Database.Name == "local") -	if err != nil { -		return nil, err -	} -	defer socket.Release() - -	s.m.RLock() -	safeOp := s.safeOp -	bypassValidation := s.bypassValidation -	s.m.RUnlock() - -	if socket.ServerInfo().MaxWireVersion >= 2 { -		// Servers with a more recent write protocol benefit from write commands. -		if op, ok := op.(*insertOp); ok && len(op.documents) > 1000 { -			var lerr LastError - -			// Maximum batch size is 1000. Must split out in separate operations for compatibility. -			all := op.documents -			for i := 0; i < len(all); i += 1000 { -				l := i + 1000 -				if l > len(all) { -					l = len(all) -				} -				op.documents = all[i:l] -				oplerr, err := c.writeOpCommand(socket, safeOp, op, ordered, bypassValidation) -				lerr.N += oplerr.N -				lerr.modified += oplerr.modified -				if err != nil { -					for ei := range oplerr.ecases { -						oplerr.ecases[ei].Index += i -					} -					lerr.ecases = append(lerr.ecases, oplerr.ecases...) -					if op.flags&1 == 0 { -						return &lerr, err -					} -				} -			} -			if len(lerr.ecases) != 0 { -				return &lerr, lerr.ecases[0].Err -			} -			return &lerr, nil -		} -		return c.writeOpCommand(socket, safeOp, op, ordered, bypassValidation) -	} else if updateOps, ok := op.(bulkUpdateOp); ok { -		var lerr LastError -		for i, updateOp := range updateOps { -			oplerr, err := c.writeOpQuery(socket, safeOp, updateOp, ordered) -			lerr.N += oplerr.N -			lerr.modified += oplerr.modified -			if err != nil { -				lerr.ecases = append(lerr.ecases, BulkErrorCase{i, err}) -				if ordered { -					break -				} -			} -		} -		if len(lerr.ecases) != 0 { -			return &lerr, lerr.ecases[0].Err -		} -		return &lerr, nil -	} else if deleteOps, ok := op.(bulkDeleteOp); ok { -		var lerr LastError -		for i, deleteOp := range deleteOps { -			oplerr, err := c.writeOpQuery(socket, safeOp, deleteOp, ordered) -			lerr.N += oplerr.N -			lerr.modified += oplerr.modified -			if err != nil { -				lerr.ecases = append(lerr.ecases, BulkErrorCase{i, err}) -				if ordered { -					break -				} -			} -		} -		if len(lerr.ecases) != 0 { -			return &lerr, lerr.ecases[0].Err -		} -		return &lerr, nil -	} -	return c.writeOpQuery(socket, safeOp, op, ordered) -} - -func (c *Collection) writeOpQuery(socket *mongoSocket, safeOp *queryOp, op interface{}, ordered bool) (lerr *LastError, err error) { -	if safeOp == nil { -		return nil, socket.Query(op) -	} - -	var mutex sync.Mutex -	var replyData []byte -	var replyErr error -	mutex.Lock() -	query := *safeOp // Copy the data. -	query.collection = c.Database.Name + ".$cmd" -	query.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { -		replyData = docData -		replyErr = err -		mutex.Unlock() -	} -	err = socket.Query(op, &query) -	if err != nil { -		return nil, err -	} -	mutex.Lock() // Wait. -	if replyErr != nil { -		return nil, replyErr // XXX TESTME -	} -	if hasErrMsg(replyData) { -		// Looks like getLastError itself failed. -		err = checkQueryError(query.collection, replyData) -		if err != nil { -			return nil, err -		} -	} -	result := &LastError{} -	bson.Unmarshal(replyData, &result) -	debugf("Result from writing query: %#v", result) -	if result.Err != "" { -		result.ecases = []BulkErrorCase{{Index: 0, Err: result}} -		if insert, ok := op.(*insertOp); ok && len(insert.documents) > 1 { -			result.ecases[0].Index = -1 -		} -		return result, result -	} -	// With MongoDB <2.6 we don't know how many actually changed, so make it the same as matched. -	result.modified = result.N -	return result, nil -} - -func (c *Collection) writeOpCommand(socket *mongoSocket, safeOp *queryOp, op interface{}, ordered, bypassValidation bool) (lerr *LastError, err error) { -	var writeConcern interface{} -	if safeOp == nil { -		writeConcern = bson.D{{"w", 0}} -	} else { -		writeConcern = safeOp.query.(*getLastError) -	} - -	var cmd bson.D -	switch op := op.(type) { -	case *insertOp: -		// http://docs.mongodb.org/manual/reference/command/insert -		cmd = bson.D{ -			{"insert", c.Name}, -			{"documents", op.documents}, -			{"writeConcern", writeConcern}, -			{"ordered", op.flags&1 == 0}, -		} -	case *updateOp: -		// http://docs.mongodb.org/manual/reference/command/update -		cmd = bson.D{ -			{"update", c.Name}, -			{"updates", []interface{}{op}}, -			{"writeConcern", writeConcern}, -			{"ordered", ordered}, -		} -	case bulkUpdateOp: -		// http://docs.mongodb.org/manual/reference/command/update -		cmd = bson.D{ -			{"update", c.Name}, -			{"updates", op}, -			{"writeConcern", writeConcern}, -			{"ordered", ordered}, -		} -	case *deleteOp: -		// http://docs.mongodb.org/manual/reference/command/delete -		cmd = bson.D{ -			{"delete", c.Name}, -			{"deletes", []interface{}{op}}, -			{"writeConcern", writeConcern}, -			{"ordered", ordered}, -		} -	case bulkDeleteOp: -		// http://docs.mongodb.org/manual/reference/command/delete -		cmd = bson.D{ -			{"delete", c.Name}, -			{"deletes", op}, -			{"writeConcern", writeConcern}, -			{"ordered", ordered}, -		} -	} -	if bypassValidation { -		cmd = append(cmd, bson.DocElem{"bypassDocumentValidation", true}) -	} - -	var result writeCmdResult -	err = c.Database.run(socket, cmd, &result) -	debugf("Write command result: %#v (err=%v)", result, err) -	ecases := result.BulkErrorCases() -	lerr = &LastError{ -		UpdatedExisting: result.N > 0 && len(result.Upserted) == 0, -		N:               result.N, - -		modified: result.NModified, -		ecases:   ecases, -	} -	if len(result.Upserted) > 0 { -		lerr.UpsertedId = result.Upserted[0].Id -	} -	if len(result.Errors) > 0 { -		e := result.Errors[0] -		lerr.Code = e.Code -		lerr.Err = e.ErrMsg -		err = lerr -	} else if result.ConcernError.Code != 0 { -		e := result.ConcernError -		lerr.Code = e.Code -		lerr.Err = e.ErrMsg -		err = lerr -	} - -	if err == nil && safeOp == nil { -		return nil, nil -	} -	return lerr, err -} - -func hasErrMsg(d []byte) bool { -	l := len(d) -	for i := 0; i+8 < l; i++ { -		if d[i] == '\x02' && d[i+1] == 'e' && d[i+2] == 'r' && d[i+3] == 'r' && d[i+4] == 'm' && d[i+5] == 's' && d[i+6] == 'g' && d[i+7] == '\x00' { -			return true -		} -	} -	return false -} diff --git a/vendor/gopkg.in/mgo.v2/socket.go b/vendor/gopkg.in/mgo.v2/socket.go deleted file mode 100644 index 8891dd5..0000000 --- a/vendor/gopkg.in/mgo.v2/socket.go +++ /dev/null @@ -1,707 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"errors" -	"fmt" -	"net" -	"sync" -	"time" - -	"gopkg.in/mgo.v2/bson" -) - -type replyFunc func(err error, reply *replyOp, docNum int, docData []byte) - -type mongoSocket struct { -	sync.Mutex -	server        *mongoServer // nil when cached -	conn          net.Conn -	timeout       time.Duration -	addr          string // For debugging only. -	nextRequestId uint32 -	replyFuncs    map[uint32]replyFunc -	references    int -	creds         []Credential -	logout        []Credential -	cachedNonce   string -	gotNonce      sync.Cond -	dead          error -	serverInfo    *mongoServerInfo -} - -type queryOpFlags uint32 - -const ( -	_ queryOpFlags = 1 << iota -	flagTailable -	flagSlaveOk -	flagLogReplay -	flagNoCursorTimeout -	flagAwaitData -) - -type queryOp struct { -	collection string -	query      interface{} -	skip       int32 -	limit      int32 -	selector   interface{} -	flags      queryOpFlags -	replyFunc  replyFunc - -	mode       Mode -	options    queryWrapper -	hasOptions bool -	serverTags []bson.D -} - -type queryWrapper struct { -	Query          interface{} "$query" -	OrderBy        interface{} "$orderby,omitempty" -	Hint           interface{} "$hint,omitempty" -	Explain        bool        "$explain,omitempty" -	Snapshot       bool        "$snapshot,omitempty" -	ReadPreference bson.D      "$readPreference,omitempty" -	MaxScan        int         "$maxScan,omitempty" -	MaxTimeMS      int         "$maxTimeMS,omitempty" -	Comment        string      "$comment,omitempty" -} - -func (op *queryOp) finalQuery(socket *mongoSocket) interface{} { -	if op.flags&flagSlaveOk != 0 && socket.ServerInfo().Mongos { -		var modeName string -		switch op.mode { -		case Strong: -			modeName = "primary" -		case Monotonic, Eventual: -			modeName = "secondaryPreferred" -		case PrimaryPreferred: -			modeName = "primaryPreferred" -		case Secondary: -			modeName = "secondary" -		case SecondaryPreferred: -			modeName = "secondaryPreferred" -		case Nearest: -			modeName = "nearest" -		default: -			panic(fmt.Sprintf("unsupported read mode: %d", op.mode)) -		} -		op.hasOptions = true -		op.options.ReadPreference = make(bson.D, 0, 2) -		op.options.ReadPreference = append(op.options.ReadPreference, bson.DocElem{"mode", modeName}) -		if len(op.serverTags) > 0 { -			op.options.ReadPreference = append(op.options.ReadPreference, bson.DocElem{"tags", op.serverTags}) -		} -	} -	if op.hasOptions { -		if op.query == nil { -			var empty bson.D -			op.options.Query = empty -		} else { -			op.options.Query = op.query -		} -		debugf("final query is %#v\n", &op.options) -		return &op.options -	} -	return op.query -} - -type getMoreOp struct { -	collection string -	limit      int32 -	cursorId   int64 -	replyFunc  replyFunc -} - -type replyOp struct { -	flags     uint32 -	cursorId  int64 -	firstDoc  int32 -	replyDocs int32 -} - -type insertOp struct { -	collection string        // "database.collection" -	documents  []interface{} // One or more documents to insert -	flags      uint32 -} - -type updateOp struct { -	Collection string      `bson:"-"` // "database.collection" -	Selector   interface{} `bson:"q"` -	Update     interface{} `bson:"u"` -	Flags      uint32      `bson:"-"` -	Multi      bool        `bson:"multi,omitempty"` -	Upsert     bool        `bson:"upsert,omitempty"` -} - -type deleteOp struct { -	Collection string      `bson:"-"` // "database.collection" -	Selector   interface{} `bson:"q"` -	Flags      uint32      `bson:"-"` -	Limit      int         `bson:"limit"` -} - -type killCursorsOp struct { -	cursorIds []int64 -} - -type requestInfo struct { -	bufferPos int -	replyFunc replyFunc -} - -func newSocket(server *mongoServer, conn net.Conn, timeout time.Duration) *mongoSocket { -	socket := &mongoSocket{ -		conn:       conn, -		addr:       server.Addr, -		server:     server, -		replyFuncs: make(map[uint32]replyFunc), -	} -	socket.gotNonce.L = &socket.Mutex -	if err := socket.InitialAcquire(server.Info(), timeout); err != nil { -		panic("newSocket: InitialAcquire returned error: " + err.Error()) -	} -	stats.socketsAlive(+1) -	debugf("Socket %p to %s: initialized", socket, socket.addr) -	socket.resetNonce() -	go socket.readLoop() -	return socket -} - -// Server returns the server that the socket is associated with. -// It returns nil while the socket is cached in its respective server. -func (socket *mongoSocket) Server() *mongoServer { -	socket.Lock() -	server := socket.server -	socket.Unlock() -	return server -} - -// ServerInfo returns details for the server at the time the socket -// was initially acquired. -func (socket *mongoSocket) ServerInfo() *mongoServerInfo { -	socket.Lock() -	serverInfo := socket.serverInfo -	socket.Unlock() -	return serverInfo -} - -// InitialAcquire obtains the first reference to the socket, either -// right after the connection is made or once a recycled socket is -// being put back in use. -func (socket *mongoSocket) InitialAcquire(serverInfo *mongoServerInfo, timeout time.Duration) error { -	socket.Lock() -	if socket.references > 0 { -		panic("Socket acquired out of cache with references") -	} -	if socket.dead != nil { -		dead := socket.dead -		socket.Unlock() -		return dead -	} -	socket.references++ -	socket.serverInfo = serverInfo -	socket.timeout = timeout -	stats.socketsInUse(+1) -	stats.socketRefs(+1) -	socket.Unlock() -	return nil -} - -// Acquire obtains an additional reference to the socket. -// The socket will only be recycled when it's released as many -// times as it's been acquired. -func (socket *mongoSocket) Acquire() (info *mongoServerInfo) { -	socket.Lock() -	if socket.references == 0 { -		panic("Socket got non-initial acquire with references == 0") -	} -	// We'll track references to dead sockets as well. -	// Caller is still supposed to release the socket. -	socket.references++ -	stats.socketRefs(+1) -	serverInfo := socket.serverInfo -	socket.Unlock() -	return serverInfo -} - -// Release decrements a socket reference. The socket will be -// recycled once its released as many times as it's been acquired. -func (socket *mongoSocket) Release() { -	socket.Lock() -	if socket.references == 0 { -		panic("socket.Release() with references == 0") -	} -	socket.references-- -	stats.socketRefs(-1) -	if socket.references == 0 { -		stats.socketsInUse(-1) -		server := socket.server -		socket.Unlock() -		socket.LogoutAll() -		// If the socket is dead server is nil. -		if server != nil { -			server.RecycleSocket(socket) -		} -	} else { -		socket.Unlock() -	} -} - -// SetTimeout changes the timeout used on socket operations. -func (socket *mongoSocket) SetTimeout(d time.Duration) { -	socket.Lock() -	socket.timeout = d -	socket.Unlock() -} - -type deadlineType int - -const ( -	readDeadline  deadlineType = 1 -	writeDeadline deadlineType = 2 -) - -func (socket *mongoSocket) updateDeadline(which deadlineType) { -	var when time.Time -	if socket.timeout > 0 { -		when = time.Now().Add(socket.timeout) -	} -	whichstr := "" -	switch which { -	case readDeadline | writeDeadline: -		whichstr = "read/write" -		socket.conn.SetDeadline(when) -	case readDeadline: -		whichstr = "read" -		socket.conn.SetReadDeadline(when) -	case writeDeadline: -		whichstr = "write" -		socket.conn.SetWriteDeadline(when) -	default: -		panic("invalid parameter to updateDeadline") -	} -	debugf("Socket %p to %s: updated %s deadline to %s ahead (%s)", socket, socket.addr, whichstr, socket.timeout, when) -} - -// Close terminates the socket use. -func (socket *mongoSocket) Close() { -	socket.kill(errors.New("Closed explicitly"), false) -} - -func (socket *mongoSocket) kill(err error, abend bool) { -	socket.Lock() -	if socket.dead != nil { -		debugf("Socket %p to %s: killed again: %s (previously: %s)", socket, socket.addr, err.Error(), socket.dead.Error()) -		socket.Unlock() -		return -	} -	logf("Socket %p to %s: closing: %s (abend=%v)", socket, socket.addr, err.Error(), abend) -	socket.dead = err -	socket.conn.Close() -	stats.socketsAlive(-1) -	replyFuncs := socket.replyFuncs -	socket.replyFuncs = make(map[uint32]replyFunc) -	server := socket.server -	socket.server = nil -	socket.gotNonce.Broadcast() -	socket.Unlock() -	for _, replyFunc := range replyFuncs { -		logf("Socket %p to %s: notifying replyFunc of closed socket: %s", socket, socket.addr, err.Error()) -		replyFunc(err, nil, -1, nil) -	} -	if abend { -		server.AbendSocket(socket) -	} -} - -func (socket *mongoSocket) SimpleQuery(op *queryOp) (data []byte, err error) { -	var wait, change sync.Mutex -	var replyDone bool -	var replyData []byte -	var replyErr error -	wait.Lock() -	op.replyFunc = func(err error, reply *replyOp, docNum int, docData []byte) { -		change.Lock() -		if !replyDone { -			replyDone = true -			replyErr = err -			if err == nil { -				replyData = docData -			} -		} -		change.Unlock() -		wait.Unlock() -	} -	err = socket.Query(op) -	if err != nil { -		return nil, err -	} -	wait.Lock() -	change.Lock() -	data = replyData -	err = replyErr -	change.Unlock() -	return data, err -} - -func (socket *mongoSocket) Query(ops ...interface{}) (err error) { - -	if lops := socket.flushLogout(); len(lops) > 0 { -		ops = append(lops, ops...) -	} - -	buf := make([]byte, 0, 256) - -	// Serialize operations synchronously to avoid interrupting -	// other goroutines while we can't really be sending data. -	// Also, record id positions so that we can compute request -	// ids at once later with the lock already held. -	requests := make([]requestInfo, len(ops)) -	requestCount := 0 - -	for _, op := range ops { -		debugf("Socket %p to %s: serializing op: %#v", socket, socket.addr, op) -		if qop, ok := op.(*queryOp); ok { -			if cmd, ok := qop.query.(*findCmd); ok { -				debugf("Socket %p to %s: find command: %#v", socket, socket.addr, cmd) -			} -		} -		start := len(buf) -		var replyFunc replyFunc -		switch op := op.(type) { - -		case *updateOp: -			buf = addHeader(buf, 2001) -			buf = addInt32(buf, 0) // Reserved -			buf = addCString(buf, op.Collection) -			buf = addInt32(buf, int32(op.Flags)) -			debugf("Socket %p to %s: serializing selector document: %#v", socket, socket.addr, op.Selector) -			buf, err = addBSON(buf, op.Selector) -			if err != nil { -				return err -			} -			debugf("Socket %p to %s: serializing update document: %#v", socket, socket.addr, op.Update) -			buf, err = addBSON(buf, op.Update) -			if err != nil { -				return err -			} - -		case *insertOp: -			buf = addHeader(buf, 2002) -			buf = addInt32(buf, int32(op.flags)) -			buf = addCString(buf, op.collection) -			for _, doc := range op.documents { -				debugf("Socket %p to %s: serializing document for insertion: %#v", socket, socket.addr, doc) -				buf, err = addBSON(buf, doc) -				if err != nil { -					return err -				} -			} - -		case *queryOp: -			buf = addHeader(buf, 2004) -			buf = addInt32(buf, int32(op.flags)) -			buf = addCString(buf, op.collection) -			buf = addInt32(buf, op.skip) -			buf = addInt32(buf, op.limit) -			buf, err = addBSON(buf, op.finalQuery(socket)) -			if err != nil { -				return err -			} -			if op.selector != nil { -				buf, err = addBSON(buf, op.selector) -				if err != nil { -					return err -				} -			} -			replyFunc = op.replyFunc - -		case *getMoreOp: -			buf = addHeader(buf, 2005) -			buf = addInt32(buf, 0) // Reserved -			buf = addCString(buf, op.collection) -			buf = addInt32(buf, op.limit) -			buf = addInt64(buf, op.cursorId) -			replyFunc = op.replyFunc - -		case *deleteOp: -			buf = addHeader(buf, 2006) -			buf = addInt32(buf, 0) // Reserved -			buf = addCString(buf, op.Collection) -			buf = addInt32(buf, int32(op.Flags)) -			debugf("Socket %p to %s: serializing selector document: %#v", socket, socket.addr, op.Selector) -			buf, err = addBSON(buf, op.Selector) -			if err != nil { -				return err -			} - -		case *killCursorsOp: -			buf = addHeader(buf, 2007) -			buf = addInt32(buf, 0) // Reserved -			buf = addInt32(buf, int32(len(op.cursorIds))) -			for _, cursorId := range op.cursorIds { -				buf = addInt64(buf, cursorId) -			} - -		default: -			panic("internal error: unknown operation type") -		} - -		setInt32(buf, start, int32(len(buf)-start)) - -		if replyFunc != nil { -			request := &requests[requestCount] -			request.replyFunc = replyFunc -			request.bufferPos = start -			requestCount++ -		} -	} - -	// Buffer is ready for the pipe.  Lock, allocate ids, and enqueue. - -	socket.Lock() -	if socket.dead != nil { -		dead := socket.dead -		socket.Unlock() -		debugf("Socket %p to %s: failing query, already closed: %s", socket, socket.addr, socket.dead.Error()) -		// XXX This seems necessary in case the session is closed concurrently -		// with a query being performed, but it's not yet tested: -		for i := 0; i != requestCount; i++ { -			request := &requests[i] -			if request.replyFunc != nil { -				request.replyFunc(dead, nil, -1, nil) -			} -		} -		return dead -	} - -	wasWaiting := len(socket.replyFuncs) > 0 - -	// Reserve id 0 for requests which should have no responses. -	requestId := socket.nextRequestId + 1 -	if requestId == 0 { -		requestId++ -	} -	socket.nextRequestId = requestId + uint32(requestCount) -	for i := 0; i != requestCount; i++ { -		request := &requests[i] -		setInt32(buf, request.bufferPos+4, int32(requestId)) -		socket.replyFuncs[requestId] = request.replyFunc -		requestId++ -	} - -	debugf("Socket %p to %s: sending %d op(s) (%d bytes)", socket, socket.addr, len(ops), len(buf)) -	stats.sentOps(len(ops)) - -	socket.updateDeadline(writeDeadline) -	_, err = socket.conn.Write(buf) -	if !wasWaiting && requestCount > 0 { -		socket.updateDeadline(readDeadline) -	} -	socket.Unlock() -	return err -} - -func fill(r net.Conn, b []byte) error { -	l := len(b) -	n, err := r.Read(b) -	for n != l && err == nil { -		var ni int -		ni, err = r.Read(b[n:]) -		n += ni -	} -	return err -} - -// Estimated minimum cost per socket: 1 goroutine + memory for the largest -// document ever seen. -func (socket *mongoSocket) readLoop() { -	p := make([]byte, 36) // 16 from header + 20 from OP_REPLY fixed fields -	s := make([]byte, 4) -	conn := socket.conn // No locking, conn never changes. -	for { -		err := fill(conn, p) -		if err != nil { -			socket.kill(err, true) -			return -		} - -		totalLen := getInt32(p, 0) -		responseTo := getInt32(p, 8) -		opCode := getInt32(p, 12) - -		// Don't use socket.server.Addr here.  socket is not -		// locked and socket.server may go away. -		debugf("Socket %p to %s: got reply (%d bytes)", socket, socket.addr, totalLen) - -		_ = totalLen - -		if opCode != 1 { -			socket.kill(errors.New("opcode != 1, corrupted data?"), true) -			return -		} - -		reply := replyOp{ -			flags:     uint32(getInt32(p, 16)), -			cursorId:  getInt64(p, 20), -			firstDoc:  getInt32(p, 28), -			replyDocs: getInt32(p, 32), -		} - -		stats.receivedOps(+1) -		stats.receivedDocs(int(reply.replyDocs)) - -		socket.Lock() -		replyFunc, ok := socket.replyFuncs[uint32(responseTo)] -		if ok { -			delete(socket.replyFuncs, uint32(responseTo)) -		} -		socket.Unlock() - -		if replyFunc != nil && reply.replyDocs == 0 { -			replyFunc(nil, &reply, -1, nil) -		} else { -			for i := 0; i != int(reply.replyDocs); i++ { -				err := fill(conn, s) -				if err != nil { -					if replyFunc != nil { -						replyFunc(err, nil, -1, nil) -					} -					socket.kill(err, true) -					return -				} - -				b := make([]byte, int(getInt32(s, 0))) - -				// copy(b, s) in an efficient way. -				b[0] = s[0] -				b[1] = s[1] -				b[2] = s[2] -				b[3] = s[3] - -				err = fill(conn, b[4:]) -				if err != nil { -					if replyFunc != nil { -						replyFunc(err, nil, -1, nil) -					} -					socket.kill(err, true) -					return -				} - -				if globalDebug && globalLogger != nil { -					m := bson.M{} -					if err := bson.Unmarshal(b, m); err == nil { -						debugf("Socket %p to %s: received document: %#v", socket, socket.addr, m) -					} -				} - -				if replyFunc != nil { -					replyFunc(nil, &reply, i, b) -				} - -				// XXX Do bound checking against totalLen. -			} -		} - -		socket.Lock() -		if len(socket.replyFuncs) == 0 { -			// Nothing else to read for now. Disable deadline. -			socket.conn.SetReadDeadline(time.Time{}) -		} else { -			socket.updateDeadline(readDeadline) -		} -		socket.Unlock() - -		// XXX Do bound checking against totalLen. -	} -} - -var emptyHeader = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - -func addHeader(b []byte, opcode int) []byte { -	i := len(b) -	b = append(b, emptyHeader...) -	// Enough for current opcodes. -	b[i+12] = byte(opcode) -	b[i+13] = byte(opcode >> 8) -	return b -} - -func addInt32(b []byte, i int32) []byte { -	return append(b, byte(i), byte(i>>8), byte(i>>16), byte(i>>24)) -} - -func addInt64(b []byte, i int64) []byte { -	return append(b, byte(i), byte(i>>8), byte(i>>16), byte(i>>24), -		byte(i>>32), byte(i>>40), byte(i>>48), byte(i>>56)) -} - -func addCString(b []byte, s string) []byte { -	b = append(b, []byte(s)...) -	b = append(b, 0) -	return b -} - -func addBSON(b []byte, doc interface{}) ([]byte, error) { -	if doc == nil { -		return append(b, 5, 0, 0, 0, 0), nil -	} -	data, err := bson.Marshal(doc) -	if err != nil { -		return b, err -	} -	return append(b, data...), nil -} - -func setInt32(b []byte, pos int, i int32) { -	b[pos] = byte(i) -	b[pos+1] = byte(i >> 8) -	b[pos+2] = byte(i >> 16) -	b[pos+3] = byte(i >> 24) -} - -func getInt32(b []byte, pos int) int32 { -	return (int32(b[pos+0])) | -		(int32(b[pos+1]) << 8) | -		(int32(b[pos+2]) << 16) | -		(int32(b[pos+3]) << 24) -} - -func getInt64(b []byte, pos int) int64 { -	return (int64(b[pos+0])) | -		(int64(b[pos+1]) << 8) | -		(int64(b[pos+2]) << 16) | -		(int64(b[pos+3]) << 24) | -		(int64(b[pos+4]) << 32) | -		(int64(b[pos+5]) << 40) | -		(int64(b[pos+6]) << 48) | -		(int64(b[pos+7]) << 56) -} diff --git a/vendor/gopkg.in/mgo.v2/stats.go b/vendor/gopkg.in/mgo.v2/stats.go deleted file mode 100644 index 59723e6..0000000 --- a/vendor/gopkg.in/mgo.v2/stats.go +++ /dev/null @@ -1,147 +0,0 @@ -// mgo - MongoDB driver for Go -// -// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -//    list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -//    this list of conditions and the following disclaimer in the documentation -//    and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -package mgo - -import ( -	"sync" -) - -var stats *Stats -var statsMutex sync.Mutex - -func SetStats(enabled bool) { -	statsMutex.Lock() -	if enabled { -		if stats == nil { -			stats = &Stats{} -		} -	} else { -		stats = nil -	} -	statsMutex.Unlock() -} - -func GetStats() (snapshot Stats) { -	statsMutex.Lock() -	snapshot = *stats -	statsMutex.Unlock() -	return -} - -func ResetStats() { -	statsMutex.Lock() -	debug("Resetting stats") -	old := stats -	stats = &Stats{} -	// These are absolute values: -	stats.Clusters = old.Clusters -	stats.SocketsInUse = old.SocketsInUse -	stats.SocketsAlive = old.SocketsAlive -	stats.SocketRefs = old.SocketRefs -	statsMutex.Unlock() -	return -} - -type Stats struct { -	Clusters     int -	MasterConns  int -	SlaveConns   int -	SentOps      int -	ReceivedOps  int -	ReceivedDocs int -	SocketsAlive int -	SocketsInUse int -	SocketRefs   int -} - -func (stats *Stats) cluster(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.Clusters += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) conn(delta int, master bool) { -	if stats != nil { -		statsMutex.Lock() -		if master { -			stats.MasterConns += delta -		} else { -			stats.SlaveConns += delta -		} -		statsMutex.Unlock() -	} -} - -func (stats *Stats) sentOps(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.SentOps += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) receivedOps(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.ReceivedOps += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) receivedDocs(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.ReceivedDocs += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) socketsInUse(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.SocketsInUse += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) socketsAlive(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.SocketsAlive += delta -		statsMutex.Unlock() -	} -} - -func (stats *Stats) socketRefs(delta int) { -	if stats != nil { -		statsMutex.Lock() -		stats.SocketRefs += delta -		statsMutex.Unlock() -	} -} diff --git a/vendor/vendor.json b/vendor/vendor.json index d7c72ad..c17ad30 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -909,36 +909,6 @@  			"revisionTime": "2016-12-22T00:19:25Z"  		},  		{ -			"checksumSHA1": "1D8GzeoFGUs5FZOoyC2DpQg8c5Y=", -			"path": "gopkg.in/mgo.v2", -			"revision": "3f83fa5005286a7fe593b055f0d7771a7dce4655", -			"revisionTime": "2016-08-18T02:01:20Z" -		}, -		{ -			"checksumSHA1": "YsB2DChSV9HxdzHaKATllAUKWSI=", -			"path": "gopkg.in/mgo.v2/bson", -			"revision": "3f83fa5005286a7fe593b055f0d7771a7dce4655", -			"revisionTime": "2016-08-18T02:01:20Z" -		}, -		{ -			"checksumSHA1": "XQsrqoNT1U0KzLxOFcAZVvqhLfk=", -			"path": "gopkg.in/mgo.v2/internal/json", -			"revision": "3f83fa5005286a7fe593b055f0d7771a7dce4655", -			"revisionTime": "2016-08-18T02:01:20Z" -		}, -		{ -			"checksumSHA1": "LEvMCnprte47qdAxWvQ/zRxVF1U=", -			"path": "gopkg.in/mgo.v2/internal/sasl", -			"revision": "3f83fa5005286a7fe593b055f0d7771a7dce4655", -			"revisionTime": "2016-08-18T02:01:20Z" -		}, -		{ -			"checksumSHA1": "+1WDRPaOphSCmRMxVPIPBV4aubc=", -			"path": "gopkg.in/mgo.v2/internal/scram", -			"revision": "3f83fa5005286a7fe593b055f0d7771a7dce4655", -			"revisionTime": "2016-08-18T02:01:20Z" -		}, -		{  			"checksumSHA1": "12GqsW8PiRPnezDDy0v4brZrndM=",  			"path": "gopkg.in/yaml.v2",  			"revision": "a5b47d31c556af34a302ce5d659e6fea44d90de0",  | 
