From b58e971e67ebe2ed41fe7bfd8b2814a0d50a683b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 18:01:33 +0000 Subject: [PATCH] chore: bump go.mongodb.org/mongo-driver from 1.10.2 to 1.11.0 Bumps [go.mongodb.org/mongo-driver](https://github.com/mongodb/mongo-go-driver) from 1.10.2 to 1.11.0. - [Release notes](https://github.com/mongodb/mongo-go-driver/releases) - [Commits](https://github.com/mongodb/mongo-go-driver/compare/v1.10.2...v1.11.0) --- updated-dependencies: - dependency-name: go.mongodb.org/mongo-driver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- .../go.mongodb.org/mongo-driver/bson/bson.go | 6 +- .../mongo-driver/bson/bsoncodec/doc.go | 12 +- .../mongo-driver/bson/bsoncodec/registry.go | 1 + .../bson/bsoncodec/struct_tag_parser.go | 42 +- .../go.mongodb.org/mongo-driver/bson/doc.go | 109 +-- .../mongo-driver/bson/primitive/decimal.go | 7 +- .../mongo-driver/bson/primitive/objectid.go | 4 +- .../mongo-driver/bson/primitive/primitive.go | 6 +- .../go.mongodb.org/mongo-driver/event/doc.go | 58 +- .../mongo-driver/internal/csot_util.go | 24 + .../mongo-driver/internal/error.go | 2 +- .../mongo-driver/internal/http.go | 38 + .../mongo-driver/mongo/change_stream.go | 64 +- .../mongo/change_stream_deployment.go | 9 +- .../mongo-driver/mongo/client.go | 505 +++--------- .../mongo-driver/mongo/client_encryption.go | 1 + .../mongo-driver/mongo/collection.go | 54 +- .../mongo-driver/mongo/cursor.go | 5 +- .../mongo-driver/mongo/database.go | 2 +- .../mongo-driver/mongo/description/server.go | 15 +- .../mongo/description/server_selector.go | 13 +- .../go.mongodb.org/mongo-driver/mongo/doc.go | 123 +-- .../mongo-driver/mongo/errors.go | 26 +- .../mongo-driver/mongo/index_view.go | 16 +- .../mongo-driver/mongo/mongo.go | 9 +- .../mongo/options/autoencryptionoptions.go | 13 +- .../mongo/options/clientencryptionoptions.go | 23 +- .../mongo/options/clientoptions.go | 25 +- .../mongo/options/datakeyoptions.go | 42 +- .../mongo-driver/mongo/session.go | 21 +- .../mongo-driver/version/version.go | 2 +- .../x/bsonx/bsoncore/document_sequence.go | 4 +- .../mongo-driver/x/mongo/driver/auth/auth.go | 4 + .../x/mongo/driver/auth/aws_conv.go | 27 +- .../x/mongo/driver/auth/mongodbaws.go | 12 +- .../x/mongo/driver/batch_cursor.go | 17 +- .../x/mongo/driver/connstring/connstring.go | 2 +- .../mongo-driver/x/mongo/driver/crypt.go | 91 ++- .../mongo-driver/x/mongo/driver/driver.go | 48 +- .../mongo-driver/x/mongo/driver/errors.go | 16 + .../x/mongo/driver/mongocrypt/mongocrypt.go | 13 +- .../driver/mongocrypt/mongocrypt_context.go | 11 + .../mongocrypt_context_not_enabled.go | 5 + .../mongocrypt/mongocrypt_not_enabled.go | 5 + .../x/mongo/driver/mongocrypt/state.go | 18 +- .../x/mongo/driver/ocsp/config.go | 8 + .../mongo-driver/x/mongo/driver/ocsp/ocsp.go | 2 +- .../x/mongo/driver/ocsp/options.go | 3 + .../mongo-driver/x/mongo/driver/operation.go | 257 +++++-- .../driver/operation/abort_transaction.go | 2 +- .../x/mongo/driver/operation/aggregate.go | 17 +- .../x/mongo/driver/operation/command.go | 2 +- .../driver/operation/commit_transaction.go | 15 +- .../x/mongo/driver/operation/count.go | 16 +- .../x/mongo/driver/operation/create.go | 2 +- .../x/mongo/driver/operation/createIndexes.go | 15 +- .../x/mongo/driver/operation/delete.go | 2 +- .../x/mongo/driver/operation/distinct.go | 14 +- .../mongo/driver/operation/drop_collection.go | 15 +- .../x/mongo/driver/operation/drop_database.go | 2 +- .../x/mongo/driver/operation/drop_indexes.go | 16 +- .../x/mongo/driver/operation/end_sessions.go | 2 +- .../x/mongo/driver/operation/find.go | 15 +- .../mongo/driver/operation/find_and_modify.go | 18 +- .../x/mongo/driver/operation/hello.go | 6 +- .../x/mongo/driver/operation/insert.go | 2 +- .../x/mongo/driver/operation/listDatabases.go | 2 +- .../driver/operation/list_collections.go | 2 +- .../x/mongo/driver/operation/list_indexes.go | 17 +- .../x/mongo/driver/operation/update.go | 2 +- .../x/mongo/driver/operation_exhaust.go | 11 +- .../x/mongo/driver/operation_legacy.go | 719 ------------------ .../x/mongo/driver/session/client_session.go | 19 +- .../x/mongo/driver/session/session_pool.go | 16 +- .../x/mongo/driver/topology/connection.go | 12 +- .../driver/topology/connection_options.go | 11 + .../x/mongo/driver/topology/errors.go | 17 +- .../x/mongo/driver/topology/fsm.go | 99 ++- .../x/mongo/driver/topology/rtt_monitor.go | 53 +- .../x/mongo/driver/topology/server.go | 15 +- .../x/mongo/driver/topology/server_options.go | 6 + .../x/mongo/driver/topology/topology.go | 95 ++- .../mongo/driver/topology/topology_options.go | 643 +++++++--------- vendor/modules.txt | 4 +- 86 files changed, 1560 insertions(+), 2170 deletions(-) create mode 100644 vendor/go.mongodb.org/mongo-driver/internal/http.go delete mode 100644 vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_legacy.go diff --git a/go.mod b/go.mod index d84fd634e..ad782a505 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.0 github.com/urfave/cli v1.22.9 - go.mongodb.org/mongo-driver v1.10.2 + go.mongodb.org/mongo-driver v1.11.0 ) require ( diff --git a/go.sum b/go.sum index 3f032273c..53b4a5953 100644 --- a/go.sum +++ b/go.sum @@ -610,8 +610,8 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.mongodb.org/mongo-driver v1.9.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.10.2 h1:4Wk3cnqOrQCn0P92L3/mmurMxzdvWWs5J9jinAVKD+k= -go.mongodb.org/mongo-driver v1.10.2/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= +go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bson.go b/vendor/go.mongodb.org/mongo-driver/bson/bson.go index 95ffc1078..a0d818582 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bson.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bson.go @@ -27,7 +27,7 @@ type Zeroer interface { // // Example usage: // -// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} +// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} type D = primitive.D // E represents a BSON element for a D. It is usually used inside a D. @@ -39,12 +39,12 @@ type E = primitive.E // // Example usage: // -// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} +// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} type M = primitive.M // An A is an ordered representation of a BSON array. // // Example usage: // -// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}} +// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}} type A = primitive.A diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go index b0ae0e23f..5f903ebea 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/doc.go @@ -17,7 +17,7 @@ // 2) A Registry that holds these ValueEncoders and ValueDecoders and provides methods for // retrieving them. // -// ValueEncoders and ValueDecoders +// # ValueEncoders and ValueDecoders // // The ValueEncoder interface is implemented by types that can encode a provided Go type to BSON. // The value to encode is provided as a reflect.Value and a bsonrw.ValueWriter is used within the @@ -31,7 +31,7 @@ // allow the use of a function with the correct signature as a ValueDecoder. A DecodeContext // instance is provided and serves similar functionality to the EncodeContext. // -// Registry and RegistryBuilder +// # Registry and RegistryBuilder // // A Registry is an immutable store for ValueEncoders, ValueDecoders, and a type map. See the Registry type // documentation for examples of registering various custom encoders and decoders. A Registry can be constructed using a @@ -53,15 +53,15 @@ // values decode as Go int32 and int64 instances, respectively, when decoding into a bson.D. The following code would // change the behavior so these values decode as Go int instances instead: // -// intType := reflect.TypeOf(int(0)) -// registryBuilder.RegisterTypeMapEntry(bsontype.Int32, intType).RegisterTypeMapEntry(bsontype.Int64, intType) +// intType := reflect.TypeOf(int(0)) +// registryBuilder.RegisterTypeMapEntry(bsontype.Int32, intType).RegisterTypeMapEntry(bsontype.Int64, intType) // // 4. Kind encoder/decoders - These can be registered using the RegisterDefaultEncoder and RegisterDefaultDecoder // methods. The registered codec will be invoked when encoding or decoding values whose reflect.Kind matches the // registered reflect.Kind as long as the value's type doesn't match a registered type or hook encoder/decoder first. // These methods should be used to change the behavior for all values for a specific kind. // -// Registry Lookup Procedure +// # Registry Lookup Procedure // // When looking up an encoder in a Registry, the precedence rules are as follows: // @@ -79,7 +79,7 @@ // rules apply for decoders, with the exception that an error of type ErrNoDecoder will be returned if no decoder is // found. // -// DefaultValueEncoders and DefaultValueDecoders +// # DefaultValueEncoders and DefaultValueDecoders // // The DefaultValueEncoders and DefaultValueDecoders types provide a full set of ValueEncoders and // ValueDecoders for handling a wide range of Go types, including all of the types within the diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go index f6f3800d4..80644023c 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/registry.go @@ -254,6 +254,7 @@ func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDe // By default, BSON documents will decode into interface{} values as bson.D. To change the default type for BSON // documents, a type map entry for bsontype.EmbeddedDocument should be registered. For example, to force BSON documents // to decode to bson.Raw, use the following code: +// // rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{})) func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder { rb.typeMap[bt] = rt diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go index 6f406c162..62708c5c7 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsoncodec/struct_tag_parser.go @@ -34,21 +34,21 @@ func (stpf StructTagParserFunc) ParseStructTags(sf reflect.StructField) (StructT // // The properties are defined below: // -// OmitEmpty Only include the field if it's not set to the zero value for the type or to -// empty slices or maps. +// 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 integer of a type larger than 32 bits value as an int32, if that's -// feasible while preserving the numeric value. +// MinSize Marshal an integer of a type larger than 32 bits value as an int32, if that's +// feasible while preserving the numeric value. // -// Truncate When unmarshaling a BSON double, it is permitted to lose precision to fit within -// a float32. +// Truncate When unmarshaling a BSON double, it is permitted to lose precision to fit within +// a float32. // -// 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. +// 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. // -// Skip This struct field should be skipped. This is usually denoted by parsing a "-" -// for the name. +// Skip This struct field should be skipped. This is usually denoted by parsing a "-" +// for the name. // // TODO(skriptble): Add tags for undefined as nil and for null as nil. type StructTags struct { @@ -67,20 +67,20 @@ type StructTags struct { // If there is no name in the struct tag fields, the struct field name is lowercased. // The tag formats accepted are: // -// "[][,[,]]" +// "[][,[,]]" // -// `(...) bson:"[][,[,]]" (...)` +// `(...) bson:"[][,[,]]" (...)` // // An example: // -// 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" -// } +// 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" +// } // // A struct tag either consisting entirely of '-' or with a bson key with a // value consisting entirely of '-' will return a StructTags with Skip true and diff --git a/vendor/go.mongodb.org/mongo-driver/bson/doc.go b/vendor/go.mongodb.org/mongo-driver/bson/doc.go index 5e3825a23..0134006d8 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/doc.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/doc.go @@ -9,21 +9,22 @@ // The BSON library handles marshalling and unmarshalling of values through a configurable codec system. For a description // of the codec system and examples of registering custom codecs, see the bsoncodec package. // -// Raw BSON +// # Raw BSON // // The Raw family of types is used to validate and retrieve elements from a slice of bytes. This // type is most useful when you want do lookups on BSON bytes without unmarshaling it into another // type. // // Example: -// var raw bson.Raw = ... // bytes from somewhere -// err := raw.Validate() -// if err != nil { return err } -// val := raw.Lookup("foo") -// i32, ok := val.Int32OK() -// // do something with i32... // -// Native Go Types +// var raw bson.Raw = ... // bytes from somewhere +// err := raw.Validate() +// if err != nil { return err } +// val := raw.Lookup("foo") +// i32, ok := val.Int32OK() +// // do something with i32... +// +// # Native Go Types // // The D and M types defined in this package can be used to build representations of BSON using native Go types. D is a // slice and M is a map. For more information about the use cases for these types, see the documentation on the type @@ -32,63 +33,64 @@ // Note that a D should not be constructed with duplicate key names, as that can cause undefined server behavior. // // Example: -// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} -// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} +// +// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} +// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} // // When decoding BSON to a D or M, the following type mappings apply when unmarshalling: // -// 1. BSON int32 unmarshals to an int32. -// 2. BSON int64 unmarshals to an int64. -// 3. BSON double unmarshals to a float64. -// 4. BSON string unmarshals to a string. -// 5. BSON boolean unmarshals to a bool. -// 6. BSON embedded document unmarshals to the parent type (i.e. D for a D, M for an M). -// 7. BSON array unmarshals to a bson.A. -// 8. BSON ObjectId unmarshals to a primitive.ObjectID. -// 9. BSON datetime unmarshals to a primitive.DateTime. -// 10. BSON binary unmarshals to a primitive.Binary. -// 11. BSON regular expression unmarshals to a primitive.Regex. -// 12. BSON JavaScript unmarshals to a primitive.JavaScript. -// 13. BSON code with scope unmarshals to a primitive.CodeWithScope. -// 14. BSON timestamp unmarshals to an primitive.Timestamp. -// 15. BSON 128-bit decimal unmarshals to an primitive.Decimal128. -// 16. BSON min key unmarshals to an primitive.MinKey. -// 17. BSON max key unmarshals to an primitive.MaxKey. -// 18. BSON undefined unmarshals to a primitive.Undefined. -// 19. BSON null unmarshals to nil. -// 20. BSON DBPointer unmarshals to a primitive.DBPointer. -// 21. BSON symbol unmarshals to a primitive.Symbol. +// 1. BSON int32 unmarshals to an int32. +// 2. BSON int64 unmarshals to an int64. +// 3. BSON double unmarshals to a float64. +// 4. BSON string unmarshals to a string. +// 5. BSON boolean unmarshals to a bool. +// 6. BSON embedded document unmarshals to the parent type (i.e. D for a D, M for an M). +// 7. BSON array unmarshals to a bson.A. +// 8. BSON ObjectId unmarshals to a primitive.ObjectID. +// 9. BSON datetime unmarshals to a primitive.DateTime. +// 10. BSON binary unmarshals to a primitive.Binary. +// 11. BSON regular expression unmarshals to a primitive.Regex. +// 12. BSON JavaScript unmarshals to a primitive.JavaScript. +// 13. BSON code with scope unmarshals to a primitive.CodeWithScope. +// 14. BSON timestamp unmarshals to an primitive.Timestamp. +// 15. BSON 128-bit decimal unmarshals to an primitive.Decimal128. +// 16. BSON min key unmarshals to an primitive.MinKey. +// 17. BSON max key unmarshals to an primitive.MaxKey. +// 18. BSON undefined unmarshals to a primitive.Undefined. +// 19. BSON null unmarshals to nil. +// 20. BSON DBPointer unmarshals to a primitive.DBPointer. +// 21. BSON symbol unmarshals to a primitive.Symbol. // // The above mappings also apply when marshalling a D or M to BSON. Some other useful marshalling mappings are: // -// 1. time.Time marshals to a BSON datetime. -// 2. int8, int16, and int32 marshal to a BSON int32. -// 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64 -// otherwise. -// 4. int64 marshals to BSON int64. -// 5. uint8 and uint16 marshal to a BSON int32. -// 6. uint, uint32, and uint64 marshal to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, -// inclusive, and BSON int64 otherwise. -// 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshalling a BSON null or -// undefined value into a string will yield the empty string.). +// 1. time.Time marshals to a BSON datetime. +// 2. int8, int16, and int32 marshal to a BSON int32. +// 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64 +// otherwise. +// 4. int64 marshals to BSON int64. +// 5. uint8 and uint16 marshal to a BSON int32. +// 6. uint, uint32, and uint64 marshal to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, +// inclusive, and BSON int64 otherwise. +// 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshalling a BSON null or +// undefined value into a string will yield the empty string.). // -// Structs +// # Structs // // Structs can be marshalled/unmarshalled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended // JSON, the following rules apply: // -// 1. Only exported fields in structs will be marshalled or unmarshalled. +// 1. Only exported fields in structs will be marshalled or unmarshalled. // -// 2. When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element. +// 2. When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element. // For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g. // `bson:"fooField"` to generate key "fooField" instead). // -// 3. An embedded struct field is marshalled as a subdocument. The key will be the lowercased name of the field's type. +// 3. An embedded struct field is marshalled as a subdocument. The key will be the lowercased name of the field's type. // -// 4. A pointer field is marshalled as the underlying type if the pointer is non-nil. If the pointer is nil, it is +// 4. A pointer field is marshalled as the underlying type if the pointer is non-nil. If the pointer is nil, it is // marshalled as a BSON null value. // -// 5. When unmarshalling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents +// 5. When unmarshalling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents // unmarshalled into an interface{} field will be unmarshalled as a D. // // The encoding of each struct field can be customized by the "bson" struct tag. @@ -98,13 +100,14 @@ // are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below: // // Example: -// structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser) +// +// structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser) // // The bson tag gives the name of the field, possibly followed by a comma-separated list of options. // The name may be empty in order to specify options without overriding the default field name. The following options can be used // to configure behavior: // -// 1. omitempty: If the omitempty struct tag is specified on a field, the field will not be marshalled if it is set to +// 1. omitempty: If the omitempty struct tag is specified on a field, the field will not be marshalled if it is set to // the zero value. Fields with language primitive types such as integers, booleans, and strings are considered empty if // their value is equal to the zero value for the type (i.e. 0 for integers, false for booleans, and "" for strings). // Slices, maps, and arrays are considered empty if they are of length zero. Interfaces and pointers are considered @@ -113,16 +116,16 @@ // never considered empty and will be marshalled as embedded documents. // NOTE: It is recommended that this tag be used for all slice and map fields. // -// 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of +// 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of // the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For other // types, this tag is ignored. // -// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled +// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled // into that field will be truncated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int, // it will be unmarshalled as 3. If this tag is not specified, the decoder will throw an error if the value cannot be // decoded without losing precision. For float64 or non-numeric types, this tag is ignored. // -// 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when +// 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when // marshalling and "un-flattened" when unmarshalling. This means that all of the fields in that struct/map will be // pulled up one level and will become top-level fields rather than being fields in a nested document. For example, if a // map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will be @@ -132,7 +135,7 @@ // This tag can be used with fields that are pointers to structs. If an inlined pointer field is nil, it will not be // marshalled. For fields that are not maps or structs, this tag is ignored. // -// Marshalling and Unmarshalling +// # Marshalling and Unmarshalling // // Manually marshalling and unmarshalling can be done with the Marshal and Unmarshal family of functions. package bson diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go index ffe4eed07..ba7c9112e 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/decimal.go @@ -191,10 +191,9 @@ func (d Decimal128) IsNaN() bool { // IsInf returns: // -// +1 d == Infinity -// 0 other case -// -1 d == -Infinity -// +// +1 d == Infinity +// 0 other case +// -1 d == -Infinity func (d Decimal128) IsInf() int { if d.h>>58&(1<<5-1) != 0x1E { return 0 diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go index 652898fea..ded367316 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/objectid.go @@ -61,7 +61,9 @@ func (id ObjectID) Timestamp() time.Time { // Hex returns the hex encoding of the ObjectID as a string. func (id ObjectID) Hex() string { - return hex.EncodeToString(id[:]) + var buf [24]byte + hex.Encode(buf[:], id[:]) + return string(buf[:]) } func (id ObjectID) String() string { diff --git a/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go b/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go index b3cba1bf9..c72ccc1c4 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/primitive/primitive.go @@ -182,7 +182,7 @@ type MaxKey struct{} // // Example usage: // -// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} +// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} type D []E // Map creates a map from the elements of the D. @@ -206,12 +206,12 @@ type E struct { // // Example usage: // -// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} +// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} type M map[string]interface{} // An A is an ordered representation of a BSON array. // // Example usage: // -// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}} +// bson.A{"bar", "world", 3.14159, bson.D{{"qux", 12345}}} type A []interface{} diff --git a/vendor/go.mongodb.org/mongo-driver/event/doc.go b/vendor/go.mongodb.org/mongo-driver/event/doc.go index 93b5ede04..da1da4d47 100644 --- a/vendor/go.mongodb.org/mongo-driver/event/doc.go +++ b/vendor/go.mongodb.org/mongo-driver/event/doc.go @@ -14,43 +14,43 @@ // CommandSucceededEvent or CommandFailedEvent through the RequestID field. For // example, the following code collects the names of started events: // -// var commandStarted []string -// cmdMonitor := &event.CommandMonitor{ -// Started: func(_ context.Context, evt *event.CommandStartedEvent) { -// commandStarted = append(commandStarted, evt.CommandName) -// }, -// } -// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetMonitor(cmdMonitor) -// client, err := mongo.Connect(context.Background(), clientOpts) +// var commandStarted []string +// cmdMonitor := &event.CommandMonitor{ +// Started: func(_ context.Context, evt *event.CommandStartedEvent) { +// commandStarted = append(commandStarted, evt.CommandName) +// }, +// } +// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetMonitor(cmdMonitor) +// client, err := mongo.Connect(context.Background(), clientOpts) // // Monitoring the connection pool requires specifying a PoolMonitor when constructing // a mongo.Client. The following code tracks the number of checked out connections: // -// var int connsCheckedOut -// poolMonitor := &event.PoolMonitor{ -// Event: func(evt *event.PoolEvent) { -// switch evt.Type { -// case event.GetSucceeded: -// connsCheckedOut++ -// case event.ConnectionReturned: -// connsCheckedOut-- -// } -// }, -// } -// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetPoolMonitor(poolMonitor) -// client, err := mongo.Connect(context.Background(), clientOpts) +// var int connsCheckedOut +// poolMonitor := &event.PoolMonitor{ +// Event: func(evt *event.PoolEvent) { +// switch evt.Type { +// case event.GetSucceeded: +// connsCheckedOut++ +// case event.ConnectionReturned: +// connsCheckedOut-- +// } +// }, +// } +// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetPoolMonitor(poolMonitor) +// client, err := mongo.Connect(context.Background(), clientOpts) // // Monitoring server changes specifying a ServerMonitor object when constructing // a mongo.Client. Different functions can be set on the ServerMonitor to // monitor different kinds of events. See ServerMonitor for more details. // The following code appends ServerHeartbeatStartedEvents to a slice: // -// var heartbeatStarted []*event.ServerHeartbeatStartedEvent -// svrMonitor := &event.ServerMonitor{ -// ServerHeartbeatStarted: func(e *event.ServerHeartbeatStartedEvent) { -// heartbeatStarted = append(heartbeatStarted, e) -// } -// } -// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetServerMonitor(svrMonitor) -// client, err := mongo.Connect(context.Background(), clientOpts) +// var heartbeatStarted []*event.ServerHeartbeatStartedEvent +// svrMonitor := &event.ServerMonitor{ +// ServerHeartbeatStarted: func(e *event.ServerHeartbeatStartedEvent) { +// heartbeatStarted = append(heartbeatStarted, e) +// } +// } +// clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetServerMonitor(svrMonitor) +// client, err := mongo.Connect(context.Background(), clientOpts) package event diff --git a/vendor/go.mongodb.org/mongo-driver/internal/csot_util.go b/vendor/go.mongodb.org/mongo-driver/internal/csot_util.go index ea07637bc..1e63257b3 100644 --- a/vendor/go.mongodb.org/mongo-driver/internal/csot_util.go +++ b/vendor/go.mongodb.org/mongo-driver/internal/csot_util.go @@ -32,3 +32,27 @@ func MakeTimeoutContext(ctx context.Context, to time.Duration) (context.Context, func IsTimeoutContext(ctx context.Context) bool { return ctx.Value(timeoutKey{}) != nil } + +// ZeroRTTMonitor implements the RTTMonitor interface and is used internally for testing. It returns 0 for all +// RTT calculations and an empty string for RTT statistics. +type ZeroRTTMonitor struct{} + +// EWMA implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) EWMA() time.Duration { + return 0 +} + +// Min implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) Min() time.Duration { + return 0 +} + +// P90 implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) P90() time.Duration { + return 0 +} + +// Stats implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) Stats() string { + return "" +} diff --git a/vendor/go.mongodb.org/mongo-driver/internal/error.go b/vendor/go.mongodb.org/mongo-driver/internal/error.go index 1fec3f183..348bcdfb1 100644 --- a/vendor/go.mongodb.org/mongo-driver/internal/error.go +++ b/vendor/go.mongodb.org/mongo-driver/internal/error.go @@ -32,7 +32,7 @@ func RolledUpErrorMessage(err error) string { return err.Error() } -//UnwrapError attempts to unwrap the error down to its root cause. +// UnwrapError attempts to unwrap the error down to its root cause. func UnwrapError(err error) error { switch tErr := err.(type) { diff --git a/vendor/go.mongodb.org/mongo-driver/internal/http.go b/vendor/go.mongodb.org/mongo-driver/internal/http.go new file mode 100644 index 000000000..13c5fbe9c --- /dev/null +++ b/vendor/go.mongodb.org/mongo-driver/internal/http.go @@ -0,0 +1,38 @@ +// Copyright (C) MongoDB, Inc. 2022-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package internal // import "go.mongodb.org/mongo-driver/internal" + +import ( + "net/http" + "time" +) + +// DefaultHTTPClient is the default HTTP client used across the driver. +var DefaultHTTPClient = &http.Client{ + // TODO(GODRIVER-2623): Use "http.DefaultTransport.Clone" once we change the minimum supported Go version to 1.13. + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + }, +} + +// CloseIdleHTTPConnections closes any connections which were previously +// connected from previous requests but are now sitting idle in +// a "keep-alive" state. It does not interrupt any connections currently +// in use. +// Borrowed from go standard library. +func CloseIdleHTTPConnections(client *http.Client) { + type closeIdler interface { + CloseIdleConnections() + } + if tr, ok := client.Transport.(closeIdler); ok { + tr.CloseIdleConnections() + } +} diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/change_stream.go b/vendor/go.mongodb.org/mongo-driver/mongo/change_stream.go index 01da999c0..82d2b5799 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/change_stream.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/change_stream.go @@ -240,7 +240,6 @@ func (cs *ChangeStream) createOperationDeployment(server driver.Server, connecti func (cs *ChangeStream) executeOperation(ctx context.Context, resuming bool) error { var server driver.Server var conn driver.Connection - var err error if server, cs.err = cs.client.deployment.SelectServer(ctx, cs.selector); cs.err != nil { return cs.Err() @@ -284,48 +283,62 @@ func (cs *ChangeStream) executeOperation(ctx context.Context, resuming bool) err // Cancel the timeout-derived context at the end of executeOperation to avoid a context leak. defer cancelFunc() } - if original := cs.aggregate.Execute(ctx); original != nil { - retryableRead := cs.client.retryReads && cs.wireVersion != nil && cs.wireVersion.Max >= 6 - if !retryableRead { - cs.err = replaceErrors(original) - return cs.err + + // Execute the aggregate, retrying on retryable errors once (1) if retryable reads are enabled and + // infinitely (-1) if context is a Timeout context. + var retries int + if cs.client.retryReads { + retries = 1 + } + if internal.IsTimeoutContext(ctx) { + retries = -1 + } + + var err error +AggregateExecuteLoop: + for { + err = cs.aggregate.Execute(ctx) + // If no error or no retries remain, do not retry. + if err == nil || retries == 0 { + break AggregateExecuteLoop } - cs.err = original - switch tt := original.(type) { + switch tt := err.(type) { case driver.Error: + // If error is not retryable, do not retry. if !tt.RetryableRead() { - break + break AggregateExecuteLoop } + // If error is retryable: subtract 1 from retries, redo server selection, checkout + // a connection, and restart loop. + retries-- server, err = cs.client.deployment.SelectServer(ctx, cs.selector) if err != nil { - break + break AggregateExecuteLoop } conn.Close() conn, err = server.Connection(ctx) if err != nil { - break + break AggregateExecuteLoop } defer conn.Close() - cs.wireVersion = conn.Description().WireVersion - if cs.wireVersion == nil || cs.wireVersion.Max < 6 { - break - } + // Update the wire version with data from the new connection. + cs.wireVersion = conn.Description().WireVersion + // Reset deployment. cs.aggregate.Deployment(cs.createOperationDeployment(server, conn)) - cs.err = cs.aggregate.Execute(ctx) - } - - if cs.err != nil { - cs.err = replaceErrors(cs.err) - return cs.Err() + default: + // Do not retry if error is not a driver error. + break AggregateExecuteLoop } - } - cs.err = nil + if err != nil { + cs.err = replaceErrors(err) + return cs.err + } cr := cs.aggregate.ResultCursorResponse() cr.Server = server @@ -419,10 +432,7 @@ func (cs *ChangeStream) createPipelineOptionsDoc() (bsoncore.Document, error) { } if cs.options.FullDocument != nil { - // Only append a default "fullDocument" field if wire version is less than 6 (3.6). Otherwise, - // the server will assume users want the default behavior, and "fullDocument" does not need to be - // specified. - if *cs.options.FullDocument != options.Default || (cs.wireVersion != nil && cs.wireVersion.Max < 6) { + if *cs.options.FullDocument != options.Default { plDoc = bsoncore.AppendStringElement(plDoc, "fullDocument", string(*cs.options.FullDocument)) } } diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/change_stream_deployment.go b/vendor/go.mongodb.org/mongo-driver/mongo/change_stream_deployment.go index 9c61123c3..4dca59f91 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/change_stream_deployment.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/change_stream_deployment.go @@ -8,7 +8,6 @@ package mongo import ( "context" - "time" "go.mongodb.org/mongo-driver/mongo/description" "go.mongodb.org/mongo-driver/x/mongo/driver" @@ -36,12 +35,8 @@ func (c *changeStreamDeployment) Connection(context.Context) (driver.Connection, return c.conn, nil } -func (c *changeStreamDeployment) MinRTT() time.Duration { - return c.server.MinRTT() -} - -func (c *changeStreamDeployment) RTT90() time.Duration { - return c.server.RTT90() +func (c *changeStreamDeployment) RTTMonitor() driver.RTTMonitor { + return c.server.RTTMonitor() } func (c *changeStreamDeployment) ProcessError(err error, conn driver.Connection) driver.ProcessErrorResult { diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/client.go b/vendor/go.mongodb.org/mongo-driver/mongo/client.go index d409135a7..d80fd1d55 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/client.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/client.go @@ -8,15 +8,15 @@ package mongo import ( "context" - "crypto/tls" "errors" "fmt" - "strings" + "net/http" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/event" + "go.mongodb.org/mongo-driver/internal" "go.mongodb.org/mongo-driver/internal/uuid" "go.mongodb.org/mongo-driver/mongo/description" "go.mongodb.org/mongo-driver/mongo/options" @@ -25,18 +25,16 @@ import ( "go.mongodb.org/mongo-driver/mongo/writeconcern" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" "go.mongodb.org/mongo-driver/x/mongo/driver" - "go.mongodb.org/mongo-driver/x/mongo/driver/auth" "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt" mcopts "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/options" - "go.mongodb.org/mongo-driver/x/mongo/driver/ocsp" "go.mongodb.org/mongo-driver/x/mongo/driver/operation" "go.mongodb.org/mongo-driver/x/mongo/driver/session" "go.mongodb.org/mongo-driver/x/mongo/driver/topology" ) const ( - defaultLocalThreshold = 15 * time.Millisecond - defaultMaxPoolSize uint64 = 100 + defaultLocalThreshold = 15 * time.Millisecond + defaultMaxPoolSize = 100 ) var ( @@ -53,22 +51,22 @@ var ( // The Client type opens and closes connections automatically and maintains a pool of idle connections. For // connection pool configuration options, see documentation for the ClientOptions type in the mongo/options package. type Client struct { - id uuid.UUID - topologyOptions []topology.Option - deployment driver.Deployment - localThreshold time.Duration - retryWrites bool - retryReads bool - clock *session.ClusterClock - readPreference *readpref.ReadPref - readConcern *readconcern.ReadConcern - writeConcern *writeconcern.WriteConcern - registry *bsoncodec.Registry - monitor *event.CommandMonitor - serverAPI *driver.ServerAPIOptions - serverMonitor *event.ServerMonitor - sessionPool *session.Pool - timeout *time.Duration + id uuid.UUID + deployment driver.Deployment + localThreshold time.Duration + retryWrites bool + retryReads bool + clock *session.ClusterClock + readPreference *readpref.ReadPref + readConcern *readconcern.ReadConcern + writeConcern *writeconcern.WriteConcern + registry *bsoncodec.Registry + monitor *event.CommandMonitor + serverAPI *driver.ServerAPIOptions + serverMonitor *event.ServerMonitor + sessionPool *session.Pool + timeout *time.Duration + httpClient *http.Client // client-side encryption fields keyVaultClientFLE *Client @@ -136,13 +134,84 @@ func NewClient(opts ...*options.ClientOptions) (*Client, error) { } client := &Client{id: id} - err = client.configure(clientOpt) + // ClusterClock + client.clock = new(session.ClusterClock) + + // LocalThreshold + client.localThreshold = defaultLocalThreshold + if clientOpt.LocalThreshold != nil { + client.localThreshold = *clientOpt.LocalThreshold + } + // Monitor + if clientOpt.Monitor != nil { + client.monitor = clientOpt.Monitor + } + // ServerMonitor + if clientOpt.ServerMonitor != nil { + client.serverMonitor = clientOpt.ServerMonitor + } + // ReadConcern + client.readConcern = readconcern.New() + if clientOpt.ReadConcern != nil { + client.readConcern = clientOpt.ReadConcern + } + // ReadPreference + client.readPreference = readpref.Primary() + if clientOpt.ReadPreference != nil { + client.readPreference = clientOpt.ReadPreference + } + // Registry + client.registry = bson.DefaultRegistry + if clientOpt.Registry != nil { + client.registry = clientOpt.Registry + } + // RetryWrites + client.retryWrites = true // retry writes on by default + if clientOpt.RetryWrites != nil { + client.retryWrites = *clientOpt.RetryWrites + } + client.retryReads = true + if clientOpt.RetryReads != nil { + client.retryReads = *clientOpt.RetryReads + } + // Timeout + client.timeout = clientOpt.Timeout + client.httpClient = clientOpt.HTTPClient + // WriteConcern + if clientOpt.WriteConcern != nil { + client.writeConcern = clientOpt.WriteConcern + } + // AutoEncryptionOptions + if clientOpt.AutoEncryptionOptions != nil { + if err := client.configureAutoEncryption(clientOpt); err != nil { + return nil, err + } + } else { + client.cryptFLE = clientOpt.Crypt + } + + // Deployment + if clientOpt.Deployment != nil { + client.deployment = clientOpt.Deployment + } + + // Set default options + if clientOpt.MaxPoolSize == nil { + clientOpt.SetMaxPoolSize(defaultMaxPoolSize) + } + + if err != nil { + return nil, err + } + + cfg, err := topology.NewConfig(clientOpt, client.clock) if err != nil { return nil, err } + client.serverAPI = topology.ServerAPIFromServerOptions(cfg.ServerOpts) if client.deployment == nil { - client.deployment, err = topology.New(client.topologyOptions...) + client.deployment, err = topology.New(cfg) if err != nil { return nil, replaceErrors(err) } @@ -212,6 +281,10 @@ func (c *Client) Disconnect(ctx context.Context) error { ctx = context.Background() } + if c.httpClient == internal.DefaultHTTPClient { + defer internal.CloseIdleHTTPConnections(c.httpClient) + } + c.endSessions(ctx) if c.mongocryptdFLE != nil { if err := c.mongocryptdFLE.disconnect(ctx); err != nil { @@ -242,6 +315,7 @@ func (c *Client) Disconnect(ctx context.Context) error { if disconnector, ok := c.deployment.(driver.Disconnector); ok { return replaceErrors(disconnector.Disconnect(ctx)) } + return nil } @@ -357,366 +431,6 @@ func (c *Client) endSessions(ctx context.Context) { } } -func (c *Client) configure(opts *options.ClientOptions) error { - var defaultOptions int - // Set default options - if opts.MaxPoolSize == nil { - defaultOptions++ - opts.SetMaxPoolSize(defaultMaxPoolSize) - } - if err := opts.Validate(); err != nil { - return err - } - - var connOpts []topology.ConnectionOption - var serverOpts []topology.ServerOption - var topologyOpts []topology.Option - - // TODO(GODRIVER-814): Add tests for topology, server, and connection related options. - - // ServerAPIOptions need to be handled early as other client and server options below reference - // c.serverAPI and serverOpts.serverAPI. - if opts.ServerAPIOptions != nil { - // convert passed in options to driver form for client. - c.serverAPI = convertToDriverAPIOptions(opts.ServerAPIOptions) - - serverOpts = append(serverOpts, topology.WithServerAPI(func(*driver.ServerAPIOptions) *driver.ServerAPIOptions { - return c.serverAPI - })) - } - - // ClusterClock - c.clock = new(session.ClusterClock) - - // Pass down URI, SRV service name, and SRV max hosts so topology can poll SRV records correctly. - topologyOpts = append(topologyOpts, - topology.WithURI(func(uri string) string { return opts.GetURI() }), - topology.WithSRVServiceName(func(srvName string) string { - if opts.SRVServiceName != nil { - return *opts.SRVServiceName - } - return "" - }), - topology.WithSRVMaxHosts(func(srvMaxHosts int) int { - if opts.SRVMaxHosts != nil { - return *opts.SRVMaxHosts - } - return 0 - }), - ) - - // AppName - var appName string - if opts.AppName != nil { - appName = *opts.AppName - - serverOpts = append(serverOpts, topology.WithServerAppName(func(string) string { - return appName - })) - } - // Compressors & ZlibLevel - var comps []string - if len(opts.Compressors) > 0 { - comps = opts.Compressors - - connOpts = append(connOpts, topology.WithCompressors( - func(compressors []string) []string { - return append(compressors, comps...) - }, - )) - - for _, comp := range comps { - switch comp { - case "zlib": - connOpts = append(connOpts, topology.WithZlibLevel(func(level *int) *int { - return opts.ZlibLevel - })) - case "zstd": - connOpts = append(connOpts, topology.WithZstdLevel(func(level *int) *int { - return opts.ZstdLevel - })) - } - } - - serverOpts = append(serverOpts, topology.WithCompressionOptions( - func(opts ...string) []string { return append(opts, comps...) }, - )) - } - - var loadBalanced bool - if opts.LoadBalanced != nil { - loadBalanced = *opts.LoadBalanced - } - - // Handshaker - var handshaker = func(driver.Handshaker) driver.Handshaker { - return operation.NewHello().AppName(appName).Compressors(comps).ClusterClock(c.clock). - ServerAPI(c.serverAPI).LoadBalanced(loadBalanced) - } - // Auth & Database & Password & Username - if opts.Auth != nil { - cred := &auth.Cred{ - Username: opts.Auth.Username, - Password: opts.Auth.Password, - PasswordSet: opts.Auth.PasswordSet, - Props: opts.Auth.AuthMechanismProperties, - Source: opts.Auth.AuthSource, - } - mechanism := opts.Auth.AuthMechanism - - if len(cred.Source) == 0 { - switch strings.ToUpper(mechanism) { - case auth.MongoDBX509, auth.GSSAPI, auth.PLAIN: - cred.Source = "$external" - default: - cred.Source = "admin" - } - } - - authenticator, err := auth.CreateAuthenticator(mechanism, cred) - if err != nil { - return err - } - - handshakeOpts := &auth.HandshakeOptions{ - AppName: appName, - Authenticator: authenticator, - Compressors: comps, - ClusterClock: c.clock, - ServerAPI: c.serverAPI, - LoadBalanced: loadBalanced, - } - if mechanism == "" { - // Required for SASL mechanism negotiation during handshake - handshakeOpts.DBUser = cred.Source + "." + cred.Username - } - if opts.AuthenticateToAnything != nil && *opts.AuthenticateToAnything { - // Authenticate arbiters - handshakeOpts.PerformAuthentication = func(serv description.Server) bool { - return true - } - } - - handshaker = func(driver.Handshaker) driver.Handshaker { - return auth.Handshaker(nil, handshakeOpts) - } - } - connOpts = append(connOpts, topology.WithHandshaker(handshaker)) - // ConnectTimeout - if opts.ConnectTimeout != nil { - serverOpts = append(serverOpts, topology.WithHeartbeatTimeout( - func(time.Duration) time.Duration { return *opts.ConnectTimeout }, - )) - connOpts = append(connOpts, topology.WithConnectTimeout( - func(time.Duration) time.Duration { return *opts.ConnectTimeout }, - )) - } - // Dialer - if opts.Dialer != nil { - connOpts = append(connOpts, topology.WithDialer( - func(topology.Dialer) topology.Dialer { return opts.Dialer }, - )) - } - // Direct - if opts.Direct != nil && *opts.Direct { - topologyOpts = append(topologyOpts, topology.WithMode( - func(topology.MonitorMode) topology.MonitorMode { return topology.SingleMode }, - )) - } - // HeartbeatInterval - if opts.HeartbeatInterval != nil { - serverOpts = append(serverOpts, topology.WithHeartbeatInterval( - func(time.Duration) time.Duration { return *opts.HeartbeatInterval }, - )) - } - // Hosts - hosts := []string{"localhost:27017"} // default host - if len(opts.Hosts) > 0 { - hosts = opts.Hosts - } - topologyOpts = append(topologyOpts, topology.WithSeedList( - func(...string) []string { return hosts }, - )) - // LocalThreshold - c.localThreshold = defaultLocalThreshold - if opts.LocalThreshold != nil { - c.localThreshold = *opts.LocalThreshold - } - // MaxConIdleTime - if opts.MaxConnIdleTime != nil { - connOpts = append(connOpts, topology.WithIdleTimeout( - func(time.Duration) time.Duration { return *opts.MaxConnIdleTime }, - )) - } - // MaxPoolSize - if opts.MaxPoolSize != nil { - serverOpts = append( - serverOpts, - topology.WithMaxConnections(func(uint64) uint64 { return *opts.MaxPoolSize }), - ) - } - // MinPoolSize - if opts.MinPoolSize != nil { - serverOpts = append( - serverOpts, - topology.WithMinConnections(func(uint64) uint64 { return *opts.MinPoolSize }), - ) - } - // MaxConnecting - if opts.MaxConnecting != nil { - serverOpts = append( - serverOpts, - topology.WithMaxConnecting(func(uint64) uint64 { return *opts.MaxConnecting }), - ) - } - // PoolMonitor - if opts.PoolMonitor != nil { - serverOpts = append( - serverOpts, - topology.WithConnectionPoolMonitor(func(*event.PoolMonitor) *event.PoolMonitor { return opts.PoolMonitor }), - ) - } - // Monitor - if opts.Monitor != nil { - c.monitor = opts.Monitor - connOpts = append(connOpts, topology.WithMonitor( - func(*event.CommandMonitor) *event.CommandMonitor { return opts.Monitor }, - )) - } - // ServerMonitor - if opts.ServerMonitor != nil { - c.serverMonitor = opts.ServerMonitor - serverOpts = append( - serverOpts, - topology.WithServerMonitor(func(*event.ServerMonitor) *event.ServerMonitor { return opts.ServerMonitor }), - ) - - topologyOpts = append( - topologyOpts, - topology.WithTopologyServerMonitor(func(*event.ServerMonitor) *event.ServerMonitor { return opts.ServerMonitor }), - ) - } - // ReadConcern - c.readConcern = readconcern.New() - if opts.ReadConcern != nil { - c.readConcern = opts.ReadConcern - } - // ReadPreference - c.readPreference = readpref.Primary() - if opts.ReadPreference != nil { - c.readPreference = opts.ReadPreference - } - // Registry - c.registry = bson.DefaultRegistry - if opts.Registry != nil { - c.registry = opts.Registry - } - // ReplicaSet - if opts.ReplicaSet != nil { - topologyOpts = append(topologyOpts, topology.WithReplicaSetName( - func(string) string { return *opts.ReplicaSet }, - )) - } - // RetryWrites - c.retryWrites = true // retry writes on by default - if opts.RetryWrites != nil { - c.retryWrites = *opts.RetryWrites - } - c.retryReads = true - if opts.RetryReads != nil { - c.retryReads = *opts.RetryReads - } - // ServerSelectionTimeout - if opts.ServerSelectionTimeout != nil { - topologyOpts = append(topologyOpts, topology.WithServerSelectionTimeout( - func(time.Duration) time.Duration { return *opts.ServerSelectionTimeout }, - )) - } - // SocketTimeout - if opts.SocketTimeout != nil { - connOpts = append( - connOpts, - topology.WithReadTimeout(func(time.Duration) time.Duration { return *opts.SocketTimeout }), - topology.WithWriteTimeout(func(time.Duration) time.Duration { return *opts.SocketTimeout }), - ) - } - // Timeout - c.timeout = opts.Timeout - // TLSConfig - if opts.TLSConfig != nil { - connOpts = append(connOpts, topology.WithTLSConfig( - func(*tls.Config) *tls.Config { - return opts.TLSConfig - }, - )) - } - // WriteConcern - if opts.WriteConcern != nil { - c.writeConcern = opts.WriteConcern - } - // AutoEncryptionOptions - if opts.AutoEncryptionOptions != nil { - if err := c.configureAutoEncryption(opts); err != nil { - return err - } - } else { - c.cryptFLE = opts.Crypt - } - - // OCSP cache - ocspCache := ocsp.NewCache() - connOpts = append( - connOpts, - topology.WithOCSPCache(func(ocsp.Cache) ocsp.Cache { return ocspCache }), - ) - - // Disable communication with external OCSP responders. - if opts.DisableOCSPEndpointCheck != nil { - connOpts = append( - connOpts, - topology.WithDisableOCSPEndpointCheck(func(bool) bool { return *opts.DisableOCSPEndpointCheck }), - ) - } - - // LoadBalanced - if opts.LoadBalanced != nil { - topologyOpts = append( - topologyOpts, - topology.WithLoadBalanced(func(bool) bool { return *opts.LoadBalanced }), - ) - serverOpts = append( - serverOpts, - topology.WithServerLoadBalanced(func(bool) bool { return *opts.LoadBalanced }), - ) - connOpts = append( - connOpts, - topology.WithConnectionLoadBalanced(func(bool) bool { return *opts.LoadBalanced }), - ) - } - - serverOpts = append( - serverOpts, - topology.WithClock(func(*session.ClusterClock) *session.ClusterClock { return c.clock }), - topology.WithConnectionOptions(func(...topology.ConnectionOption) []topology.ConnectionOption { return connOpts }), - ) - topologyOpts = append(topologyOpts, topology.WithServerOptions( - func(...topology.ServerOption) []topology.ServerOption { return serverOpts }, - )) - c.topologyOptions = topologyOpts - - // Deployment - if opts.Deployment != nil { - // topology options: WithSeedlist, WithURI, WithSRVServiceName, WithSRVMaxHosts, and WithServerOptions - // server options: WithClock and WithConnectionOptions + default maxPoolSize - if len(serverOpts) > 2+defaultOptions || len(topologyOpts) > 5 { - return errors.New("cannot specify topology or server options with a deployment") - } - c.deployment = opts.Deployment - } - - return nil -} - func (c *Client) configureAutoEncryption(clientOpts *options.ClientOptions) error { c.encryptedFieldsMap = clientOpts.AutoEncryptionOptions.EncryptedFieldsMap if err := c.configureKeyVaultClientFLE(clientOpts); err != nil { @@ -895,6 +609,7 @@ func (c *Client) configureCryptFLE(mc *mongocrypt.MongoCrypt, opts *options.Auto KeyFn: kr.cryptKeys, MarkFn: c.mongocryptdFLE.markCommand, TLSConfig: opts.TLSConfig, + HTTPClient: opts.HTTPClient, BypassAutoEncryption: bypass, }) } @@ -907,18 +622,6 @@ func (c *Client) validSession(sess *session.Client) error { return nil } -// convertToDriverAPIOptions converts a options.ServerAPIOptions instance to a driver.ServerAPIOptions. -func convertToDriverAPIOptions(s *options.ServerAPIOptions) *driver.ServerAPIOptions { - driverOpts := driver.NewServerAPIOptions(string(s.ServerAPIVersion)) - if s.Strict != nil { - driverOpts.SetStrict(*s.Strict) - } - if s.DeprecationErrors != nil { - driverOpts.SetDeprecationErrors(*s.DeprecationErrors) - } - return driverOpts -} - // Database returns a handle for a database with the given name configured with the given DatabaseOptions. func (c *Client) Database(name string, opts ...*options.DatabaseOptions) *Database { return newDatabase(c, name, opts...) @@ -1099,7 +802,15 @@ func (c *Client) Watch(ctx context.Context, pipeline interface{}, // NumberSessionsInProgress returns the number of sessions that have been started for this client but have not been // closed (i.e. EndSession has not been called). func (c *Client) NumberSessionsInProgress() int { - return c.sessionPool.CheckedOut() + // The underlying session pool uses an int64 for checkedOut to allow atomic + // access. We convert to an int here to maintain backward compatibility with + // older versions of the driver that did not atomically access checkedOut. + return int(c.sessionPool.CheckedOut()) +} + +// Timeout returns the timeout set for this client. +func (c *Client) Timeout() *time.Duration { + return c.timeout } func (c *Client) createBaseCursorOptions() driver.CursorOptions { diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/client_encryption.go b/vendor/go.mongodb.org/mongo-driver/mongo/client_encryption.go index a9794d60b..59c550b95 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/client_encryption.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/client_encryption.go @@ -66,6 +66,7 @@ func NewClientEncryption(keyVaultClient *Client, opts ...*options.ClientEncrypti KeyFn: kr.cryptKeys, CollInfoFn: cir.cryptCollInfo, TLSConfig: ceo.TLSConfig, + HTTPClient: ceo.HTTPClient, }) return ce, nil diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/collection.go b/vendor/go.mongodb.org/mongo-driver/mongo/collection.go index aa3ffbe95..2a697064c 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/collection.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/collection.go @@ -846,7 +846,8 @@ func aggregate(a aggregateParams) (cur *Cursor, err error) { Crypt(a.client.cryptFLE). ServerAPI(a.client.serverAPI). HasOutputStage(hasOutputStage). - Timeout(a.client.timeout) + Timeout(a.client.timeout). + MaxTime(ao.MaxTime) if ao.AllowDiskUse != nil { op.AllowDiskUse(*ao.AllowDiskUse) @@ -862,9 +863,6 @@ func aggregate(a aggregateParams) (cur *Cursor, err error) { if ao.Collation != nil { op.Collation(bsoncore.Document(ao.Collation.ToDocument())) } - if ao.MaxTime != nil { - op.MaxTimeMS(int64(*ao.MaxTime / time.Millisecond)) - } if ao.MaxAwaitTime != nil { cursorOpts.MaxTimeMS = int64(*ao.MaxAwaitTime / time.Millisecond) } @@ -971,16 +969,13 @@ func (coll *Collection) CountDocuments(ctx context.Context, filter interface{}, op := operation.NewAggregate(pipelineArr).Session(sess).ReadConcern(rc).ReadPreference(coll.readPreference). CommandMonitor(coll.client.monitor).ServerSelector(selector).ClusterClock(coll.client.clock).Database(coll.db.name). Collection(coll.name).Deployment(coll.client.deployment).Crypt(coll.client.cryptFLE).ServerAPI(coll.client.serverAPI). - Timeout(coll.client.timeout) + Timeout(coll.client.timeout).MaxTime(countOpts.MaxTime) if countOpts.Collation != nil { op.Collation(bsoncore.Document(countOpts.Collation.ToDocument())) } if countOpts.Comment != nil { op.Comment(*countOpts.Comment) } - if countOpts.MaxTime != nil { - op.MaxTimeMS(int64(*countOpts.MaxTime / time.Millisecond)) - } if countOpts.Hint != nil { hintVal, err := transformValue(coll.registry, countOpts.Hint, false, "hint") if err != nil { @@ -1052,14 +1047,15 @@ func (coll *Collection) EstimatedDocumentCount(ctx context.Context, rc = nil } + co := options.MergeEstimatedDocumentCountOptions(opts...) + selector := makeReadPrefSelector(sess, coll.readSelector, coll.client.localThreshold) op := operation.NewCount().Session(sess).ClusterClock(coll.client.clock). Database(coll.db.name).Collection(coll.name).CommandMonitor(coll.client.monitor). Deployment(coll.client.deployment).ReadConcern(rc).ReadPreference(coll.readPreference). ServerSelector(selector).Crypt(coll.client.cryptFLE).ServerAPI(coll.client.serverAPI). - Timeout(coll.client.timeout) + Timeout(coll.client.timeout).MaxTime(co.MaxTime) - co := options.MergeEstimatedDocumentCountOptions(opts...) if co.Comment != nil { comment, err := transformValue(coll.registry, co.Comment, false, "comment") if err != nil { @@ -1067,9 +1063,7 @@ func (coll *Collection) EstimatedDocumentCount(ctx context.Context, } op = op.Comment(comment) } - if co.MaxTime != nil { - op = op.MaxTimeMS(int64(*co.MaxTime / time.Millisecond)) - } + retry := driver.RetryNone if coll.client.retryReads { retry = driver.RetryOncePerCommand @@ -1077,7 +1071,6 @@ func (coll *Collection) EstimatedDocumentCount(ctx context.Context, op.Retry(retry) err = op.Execute(ctx) - return op.Result().N, replaceErrors(err) } @@ -1131,7 +1124,7 @@ func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter i Database(coll.db.name).Collection(coll.name).CommandMonitor(coll.client.monitor). Deployment(coll.client.deployment).ReadConcern(rc).ReadPreference(coll.readPreference). ServerSelector(selector).Crypt(coll.client.cryptFLE).ServerAPI(coll.client.serverAPI). - Timeout(coll.client.timeout) + Timeout(coll.client.timeout).MaxTime(option.MaxTime) if option.Collation != nil { op.Collation(bsoncore.Document(option.Collation.ToDocument())) @@ -1143,9 +1136,6 @@ func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter i } op.Comment(comment) } - if option.MaxTime != nil { - op.MaxTimeMS(int64(*option.MaxTime / time.Millisecond)) - } retry := driver.RetryNone if coll.client.retryReads { retry = driver.RetryOncePerCommand @@ -1225,17 +1215,17 @@ func (coll *Collection) Find(ctx context.Context, filter interface{}, rc = nil } + fo := options.MergeFindOptions(opts...) + selector := makeReadPrefSelector(sess, coll.readSelector, coll.client.localThreshold) op := operation.NewFind(f). Session(sess).ReadConcern(rc).ReadPreference(coll.readPreference). CommandMonitor(coll.client.monitor).ServerSelector(selector). ClusterClock(coll.client.clock).Database(coll.db.name).Collection(coll.name). Deployment(coll.client.deployment).Crypt(coll.client.cryptFLE).ServerAPI(coll.client.serverAPI). - Timeout(coll.client.timeout) + Timeout(coll.client.timeout).MaxTime(fo.MaxTime) - fo := options.MergeFindOptions(opts...) cursorOpts := coll.client.createBaseCursorOptions() - if fo.AllowDiskUse != nil { op.AllowDiskUse(*fo.AllowDiskUse) } @@ -1300,9 +1290,6 @@ func (coll *Collection) Find(ctx context.Context, filter interface{}, if fo.MaxAwaitTime != nil { cursorOpts.MaxTimeMS = int64(*fo.MaxAwaitTime / time.Millisecond) } - if fo.MaxTime != nil { - op.MaxTimeMS(int64(*fo.MaxTime / time.Millisecond)) - } if fo.Min != nil { min, err := transformBsoncoreDocument(coll.registry, fo.Min, true, "min") if err != nil { @@ -1482,7 +1469,8 @@ func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{} return &SingleResult{err: err} } fod := options.MergeFindOneAndDeleteOptions(opts...) - op := operation.NewFindAndModify(f).Remove(true).ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout) + op := operation.NewFindAndModify(f).Remove(true).ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout). + MaxTime(fod.MaxTime) if fod.Collation != nil { op = op.Collation(bsoncore.Document(fod.Collation.ToDocument())) } @@ -1493,9 +1481,6 @@ func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{} } op = op.Comment(comment) } - if fod.MaxTime != nil { - op = op.MaxTimeMS(int64(*fod.MaxTime / time.Millisecond)) - } if fod.Projection != nil { proj, err := transformBsoncoreDocument(coll.registry, fod.Projection, true, "projection") if err != nil { @@ -1559,7 +1544,7 @@ func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{ fo := options.MergeFindOneAndReplaceOptions(opts...) op := operation.NewFindAndModify(f).Update(bsoncore.Value{Type: bsontype.EmbeddedDocument, Data: r}). - ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout) + ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout).MaxTime(fo.MaxTime) if fo.BypassDocumentValidation != nil && *fo.BypassDocumentValidation { op = op.BypassDocumentValidation(*fo.BypassDocumentValidation) } @@ -1573,9 +1558,6 @@ func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{ } op = op.Comment(comment) } - if fo.MaxTime != nil { - op = op.MaxTimeMS(int64(*fo.MaxTime / time.Millisecond)) - } if fo.Projection != nil { proj, err := transformBsoncoreDocument(coll.registry, fo.Projection, true, "projection") if err != nil { @@ -1642,7 +1624,8 @@ func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{} } fo := options.MergeFindOneAndUpdateOptions(opts...) - op := operation.NewFindAndModify(f).ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout) + op := operation.NewFindAndModify(f).ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout). + MaxTime(fo.MaxTime) u, err := transformUpdateValue(coll.registry, update, true) if err != nil { @@ -1670,9 +1653,6 @@ func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{} } op = op.Comment(comment) } - if fo.MaxTime != nil { - op = op.MaxTimeMS(int64(*fo.MaxTime / time.Millisecond)) - } if fo.Projection != nil { proj, err := transformBsoncoreDocument(coll.registry, fo.Projection, true, "projection") if err != nil { @@ -1845,7 +1825,7 @@ func (coll *Collection) drop(ctx context.Context) error { ServerSelector(selector).ClusterClock(coll.client.clock). Database(coll.db.name).Collection(coll.name). Deployment(coll.client.deployment).Crypt(coll.client.cryptFLE). - ServerAPI(coll.client.serverAPI) + ServerAPI(coll.client.serverAPI).Timeout(coll.client.timeout) err = op.Execute(ctx) // ignore namespace not found erorrs diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/cursor.go b/vendor/go.mongodb.org/mongo-driver/mongo/cursor.go index d21005fed..99f869515 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/cursor.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/cursor.go @@ -246,7 +246,10 @@ func (c *Cursor) All(ctx context.Context, results interface{}) error { var index int var err error - defer c.Close(ctx) + // Defer a call to Close to try to clean up the cursor server-side when all + // documents have not been exhausted. Use context.Background() to ensure Close + // completes even if the context passed to All has errored. + defer c.Close(context.Background()) batch := c.batch // exhaust the current batch before iterating the batch cursor for { diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/database.go b/vendor/go.mongodb.org/mongo-driver/mongo/database.go index 57b5417fd..cd93fb860 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/database.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/database.go @@ -745,7 +745,7 @@ func (db *Database) createCollectionOperation(name string, opts ...*options.Crea // // The viewName parameter specifies the name of the view to create. // -// The viewOn parameter specifies the name of the collection or view on which this view will be created +// # The viewOn parameter specifies the name of the collection or view on which this view will be created // // The pipeline parameter specifies an aggregation pipeline that will be exececuted against the source collection or // view to create this view. diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/description/server.go b/vendor/go.mongodb.org/mongo-driver/mongo/description/server.go index 405efe94b..a20c86ac9 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/description/server.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/description/server.go @@ -40,6 +40,7 @@ type Server struct { HeartbeatInterval time.Duration HelloOK bool Hosts []string + IsCryptd bool LastError error LastUpdateTime time.Time LastWriteTime time.Time @@ -72,7 +73,7 @@ func NewServer(addr address.Address, response bson.Raw) Server { var ok bool var isReplicaSet, isWritablePrimary, hidden, secondary, arbiterOnly bool var msg string - var version VersionRange + var versionRange VersionRange for _, element := range elements { switch element.Key() { case "arbiters": @@ -101,6 +102,12 @@ func NewServer(addr address.Address, response bson.Raw) Server { desc.LastError = fmt.Errorf("expected 'electionId' to be a objectID but it's a BSON %s", element.Value().Type) return desc } + case "iscryptd": + desc.IsCryptd, ok = element.Value().BooleanOK() + if !ok { + desc.LastError = fmt.Errorf("expected 'iscryptd' to be a boolean but it's a BSON %s", element.Value().Type) + return desc + } case "helloOk": desc.HelloOK, ok = element.Value().BooleanOK() if !ok { @@ -189,13 +196,13 @@ func NewServer(addr address.Address, response bson.Raw) Server { } desc.CanonicalAddr = address.Address(me).Canonicalize() case "maxWireVersion": - version.Max, ok = element.Value().AsInt32OK() + versionRange.Max, ok = element.Value().AsInt32OK() if !ok { desc.LastError = fmt.Errorf("expected 'maxWireVersion' to be an integer but it's a BSON %s", element.Value().Type) return desc } case "minWireVersion": - version.Min, ok = element.Value().AsInt32OK() + versionRange.Min, ok = element.Value().AsInt32OK() if !ok { desc.LastError = fmt.Errorf("expected 'minWireVersion' to be an integer but it's a BSON %s", element.Value().Type) return desc @@ -321,7 +328,7 @@ func NewServer(addr address.Address, response bson.Raw) Server { desc.Kind = Mongos } - desc.WireVersion = &version + desc.WireVersion = &versionRange return desc } diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/description/server_selector.go b/vendor/go.mongodb.org/mongo-driver/mongo/description/server_selector.go index 8e810cb9c..df5e77a45 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/description/server_selector.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/description/server_selector.go @@ -296,13 +296,18 @@ func selectByTagSet(candidates []Server, tagSets []tag.Set) []Server { } func selectByKind(candidates []Server, kind ServerKind) []Server { - var result []Server - for _, s := range candidates { + // Record the indices of viable candidates first and then append those to the returned slice + // to avoid appending costly Server structs directly as an optimization. + viableIndexes := make([]int, 0, len(candidates)) + for i, s := range candidates { if s.Kind == kind { - result = append(result, s) + viableIndexes = append(viableIndexes, i) } } - + result := make([]Server, len(viableIndexes)) + for i, idx := range viableIndexes { + result[i] = candidates[idx] + } return result } diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/doc.go b/vendor/go.mongodb.org/mongo-driver/mongo/doc.go index e6e4d9e5f..39bb53099 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/doc.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/doc.go @@ -11,67 +11,67 @@ // Basic usage of the driver starts with creating a Client from a connection // string. To do so, call Connect: // -// ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) -// defer cancel() -// client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://foo:bar@localhost:27017")) -// if err != nil { return err } +// ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) +// defer cancel() +// client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://foo:bar@localhost:27017")) +// if err != nil { return err } // // This will create a new client and start monitoring the MongoDB server on localhost. // The Database and Collection types can be used to access the database: // -// collection := client.Database("baz").Collection("qux") +// collection := client.Database("baz").Collection("qux") // // A Collection can be used to query the database or insert documents: // -// res, err := collection.InsertOne(context.Background(), bson.M{"hello": "world"}) -// if err != nil { return err } -// id := res.InsertedID +// res, err := collection.InsertOne(context.Background(), bson.M{"hello": "world"}) +// if err != nil { return err } +// id := res.InsertedID // // Several methods return a cursor, which can be used like this: // -// cur, err := collection.Find(context.Background(), bson.D{}) -// if err != nil { log.Fatal(err) } -// defer cur.Close(context.Background()) -// for cur.Next(context.Background()) { -// // To decode into a struct, use cursor.Decode() -// result := struct{ -// Foo string -// Bar int32 -// }{} -// err := cur.Decode(&result) -// if err != nil { log.Fatal(err) } -// // do something with result... -// -// // To get the raw bson bytes use cursor.Current -// raw := cur.Current -// // do something with raw... -// } -// if err := cur.Err(); err != nil { -// return err -// } +// cur, err := collection.Find(context.Background(), bson.D{}) +// if err != nil { log.Fatal(err) } +// defer cur.Close(context.Background()) +// for cur.Next(context.Background()) { +// // To decode into a struct, use cursor.Decode() +// result := struct{ +// Foo string +// Bar int32 +// }{} +// err := cur.Decode(&result) +// if err != nil { log.Fatal(err) } +// // do something with result... +// +// // To get the raw bson bytes use cursor.Current +// raw := cur.Current +// // do something with raw... +// } +// if err := cur.Err(); err != nil { +// return err +// } // // Cursor.All will decode all of the returned elements at once: // -// var results []struct{ -// Foo string -// Bar int32 -// } -// if err = cur.All(context.Background(), &results); err != nil { -// log.Fatal(err) -// } -// // do something with results... +// var results []struct{ +// Foo string +// Bar int32 +// } +// if err = cur.All(context.Background(), &results); err != nil { +// log.Fatal(err) +// } +// // do something with results... // // Methods that only return a single document will return a *SingleResult, which works // like a *sql.Row: // -// result := struct{ -// Foo string -// Bar int32 -// }{} -// filter := bson.D{{"hello", "world"}} -// err := collection.FindOne(context.Background(), filter).Decode(&result) -// if err != nil { return err } -// // do something with result... +// result := struct{ +// Foo string +// Bar int32 +// }{} +// filter := bson.D{{"hello", "world"}} +// err := collection.FindOne(context.Background(), filter).Decode(&result) +// if err != nil { return err } +// // do something with result... // // All Client, Collection, and Database methods that take parameters of type interface{} // will return ErrNilDocument if nil is passed in for an interface{}. @@ -79,7 +79,7 @@ // Additional examples can be found under the examples directory in the driver's repository and // on the MongoDB website. // -// Error Handling +// # Error Handling // // Errors from the MongoDB server will implement the ServerError interface, which has functions to check for specific // error codes, labels, and message substrings. These can be used to check for and handle specific errors. Some methods, @@ -87,23 +87,26 @@ // functions will return true if any of the contained errors satisfy the check. // // There are also helper functions to check for certain specific types of errors: -// IsDuplicateKeyError(error) -// IsNetworkError(error) -// IsTimeout(error) // -// Potential DNS Issues +// IsDuplicateKeyError(error) +// IsNetworkError(error) +// IsTimeout(error) +// +// # Potential DNS Issues // // Building with Go 1.11+ and using connection strings with the "mongodb+srv"[1] scheme is // incompatible with some DNS servers in the wild due to the change introduced in // https://github.com/golang/go/issues/10622. If you receive an error with the message "cannot // unmarshal DNS message" while running an operation, we suggest you use a different DNS server. // -// Client Side Encryption +// # Client Side Encryption // // Client-side encryption is a new feature in MongoDB 4.2 that allows specific data fields to be encrypted. Using this -// feature requires specifying the "cse" build tag during compilation. +// feature requires specifying the "cse" build tag during compilation: +// +// go build -tags cse // -// Note: Auto encryption is an enterprise-only feature. +// Note: Auto encryption is an enterprise- and Atlas-only feature. // // The libmongocrypt C library is required when using client-side encryption. Specific versions of libmongocrypt // are required for different versions of the Go Driver: @@ -131,16 +134,16 @@ // // 3. Windows: // -// mkdir -p c:/libmongocrypt/bin -// mkdir -p c:/libmongocrypt/include +// mkdir -p c:/libmongocrypt/bin +// mkdir -p c:/libmongocrypt/include // -// // Run the curl command in an empty directory as it will create new directories when unpacked. -// curl https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt.tar.gz --output libmongocrypt.tar.gz -// tar -xvzf libmongocrypt.tar.gz +// // Run the curl command in an empty directory as it will create new directories when unpacked. +// curl https://s3.amazonaws.com/mciuploads/libmongocrypt/windows/latest_release/libmongocrypt.tar.gz --output libmongocrypt.tar.gz +// tar -xvzf libmongocrypt.tar.gz // -// cp ./bin/mongocrypt.dll c:/libmongocrypt/bin -// cp ./include/mongocrypt/*.h c:/libmongocrypt/include -// export PATH=$PATH:/cygdrive/c/libmongocrypt/bin +// cp ./bin/mongocrypt.dll c:/libmongocrypt/bin +// cp ./include/mongocrypt/*.h c:/libmongocrypt/include +// export PATH=$PATH:/cygdrive/c/libmongocrypt/bin // // libmongocrypt communicates with the mongocryptd process or mongo_crypt shared library for automatic encryption. // See AutoEncryptionOpts.SetExtraOptions for options to configure use of mongocryptd or mongo_crypt. diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/errors.go b/vendor/go.mongodb.org/mongo-driver/mongo/errors.go index 33e23573f..620022ee5 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/errors.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/errors.go @@ -46,6 +46,11 @@ func (e ErrMapForOrderedArgument) Error() string { } func replaceErrors(err error) error { + // Return nil when err is nil to avoid costly reflection logic below. + if err == nil { + return nil + } + if err == topology.ErrTopologyClosed { return ErrClientDisconnected } @@ -107,6 +112,19 @@ func IsTimeout(err error) bool { if err == driver.ErrDeadlineWouldBeExceeded { return true } + if err == topology.ErrServerSelectionTimeout { + return true + } + if _, ok := err.(topology.WaitQueueTimeoutError); ok { + return true + } + if ce, ok := err.(CommandError); ok && ce.IsMaxTimeMSExpiredError() { + return true + } + if we, ok := err.(WriteException); ok && we.WriteConcernError != nil && + we.WriteConcernError.IsMaxTimeMSExpiredError() { + return true + } if ne, ok := err.(net.Error); ok { return ne.Timeout() } @@ -365,6 +383,11 @@ func (wce WriteConcernError) Error() string { return wce.Message } +// IsMaxTimeMSExpiredError returns true if the error is a MaxTimeMSExpired error. +func (wce WriteConcernError) IsMaxTimeMSExpiredError() bool { + return wce.Code == 50 +} + // WriteException is the error type returned by the InsertOne, DeleteOne, DeleteMany, UpdateOne, UpdateMany, and // ReplaceOne operations. type WriteException struct { @@ -619,7 +642,8 @@ const batchErrorsTargetLength = 2000 // to the end. // // Example format: -// "[message 1, message 2, +8 more errors...]" +// +// "[message 1, message 2, +8 more errors...]" func joinBatchErrors(errs []error) string { var buf bytes.Buffer fmt.Fprint(&buf, "[") diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/index_view.go b/vendor/go.mongodb.org/mongo-driver/mongo/index_view.go index a393c7e7c..6bb33f07b 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/index_view.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/index_view.go @@ -12,7 +12,6 @@ import ( "errors" "fmt" "strconv" - "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/bsontype" @@ -104,9 +103,7 @@ func (iv IndexView) List(ctx context.Context, opts ...*options.ListIndexesOption op = op.BatchSize(*lio.BatchSize) cursorOpts.BatchSize = *lio.BatchSize } - if lio.MaxTime != nil { - op = op.MaxTimeMS(int64(*lio.MaxTime / time.Millisecond)) - } + op = op.MaxTime(lio.MaxTime) retry := driver.RetryNone if iv.coll.client.retryReads { retry = driver.RetryOncePerCommand @@ -258,11 +255,7 @@ func (iv IndexView) CreateMany(ctx context.Context, models []IndexModel, opts .. Session(sess).WriteConcern(wc).ClusterClock(iv.coll.client.clock). Database(iv.coll.db.name).Collection(iv.coll.name).CommandMonitor(iv.coll.client.monitor). Deployment(iv.coll.client.deployment).ServerSelector(selector).ServerAPI(iv.coll.client.serverAPI). - Timeout(iv.coll.client.timeout) - - if option.MaxTime != nil { - op.MaxTimeMS(int64(*option.MaxTime / time.Millisecond)) - } + Timeout(iv.coll.client.timeout).MaxTime(option.MaxTime) if option.CommitQuorum != nil { commitQuorum, err := transformValue(iv.coll.registry, option.CommitQuorum, true, "commitQuorum") if err != nil { @@ -403,10 +396,7 @@ func (iv IndexView) drop(ctx context.Context, name string, opts ...*options.Drop ServerSelector(selector).ClusterClock(iv.coll.client.clock). Database(iv.coll.db.name).Collection(iv.coll.name). Deployment(iv.coll.client.deployment).ServerAPI(iv.coll.client.serverAPI). - Timeout(iv.coll.client.timeout) - if dio.MaxTime != nil { - op.MaxTimeMS(int64(*dio.MaxTime / time.Millisecond)) - } + Timeout(iv.coll.client.timeout).MaxTime(dio.MaxTime) err = op.Execute(ctx) if err != nil { diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/mongo.go b/vendor/go.mongodb.org/mongo-driver/mongo/mongo.go index 80282527e..2fa5e54ae 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/mongo.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/mongo.go @@ -65,11 +65,10 @@ func (me MarshalError) Error() string { // // Example usage: // -// mongo.Pipeline{ -// {{"$group", bson.D{{"_id", "$state"}, {"totalPop", bson.D{{"$sum", "$pop"}}}}}}, -// {{"$match", bson.D{{"totalPop", bson.D{{"$gte", 10*1000*1000}}}}}}, -// } -// +// mongo.Pipeline{ +// {{"$group", bson.D{{"_id", "$state"}, {"totalPop", bson.D{{"$sum", "$pop"}}}}}}, +// {{"$match", bson.D{{"totalPop", bson.D{{"$gte", 10*1000*1000}}}}}}, +// } type Pipeline []bson.D // transformAndEnsureID is a hack that makes it easy to get a RawValue as the _id value. diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/autoencryptionoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/autoencryptionoptions.go index 375d89991..f42714b3d 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/autoencryptionoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/autoencryptionoptions.go @@ -8,6 +8,9 @@ package options import ( "crypto/tls" + "net/http" + + "go.mongodb.org/mongo-driver/internal" ) // AutoEncryptionOptions represents options used to configure auto encryption/decryption behavior for a mongo.Client @@ -32,13 +35,16 @@ type AutoEncryptionOptions struct { BypassAutoEncryption *bool ExtraOptions map[string]interface{} TLSConfig map[string]*tls.Config + HTTPClient *http.Client EncryptedFieldsMap map[string]interface{} BypassQueryAnalysis *bool } // AutoEncryption creates a new AutoEncryptionOptions configured with default values. func AutoEncryption() *AutoEncryptionOptions { - return &AutoEncryptionOptions{} + return &AutoEncryptionOptions{ + HTTPClient: internal.DefaultHTTPClient, + } } // SetKeyVaultClientOptions specifies options for the client used to communicate with the key vault collection. @@ -94,7 +100,7 @@ func (a *AutoEncryptionOptions) SetBypassAutoEncryption(bypass bool) *AutoEncryp // SetExtraOptions specifies a map of options to configure the mongocryptd process or mongo_crypt shared library. // -// Supported Extra Options +// # Supported Extra Options // // "mongocryptdURI" - The mongocryptd URI. Allows setting a custom URI used to communicate with the // mongocryptd process. The default is "mongodb://localhost:27020", which works with the default @@ -194,6 +200,9 @@ func MergeAutoEncryptionOptions(opts ...*AutoEncryptionOptions) *AutoEncryptionO if opt.BypassQueryAnalysis != nil { aeo.BypassQueryAnalysis = opt.BypassQueryAnalysis } + if opt.HTTPClient != nil { + aeo.HTTPClient = opt.HTTPClient + } } return aeo diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientencryptionoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientencryptionoptions.go index b8f6e8710..81ea42d42 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientencryptionoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientencryptionoptions.go @@ -9,6 +9,9 @@ package options import ( "crypto/tls" "fmt" + "net/http" + + "go.mongodb.org/mongo-driver/internal" ) // ClientEncryptionOptions represents all possible options used to configure a ClientEncryption instance. @@ -16,11 +19,14 @@ type ClientEncryptionOptions struct { KeyVaultNamespace string KmsProviders map[string]map[string]interface{} TLSConfig map[string]*tls.Config + HTTPClient *http.Client } // ClientEncryption creates a new ClientEncryptionOptions instance. func ClientEncryption() *ClientEncryptionOptions { - return &ClientEncryptionOptions{} + return &ClientEncryptionOptions{ + HTTPClient: internal.DefaultHTTPClient, + } } // SetKeyVaultNamespace specifies the namespace of the key vault collection. This is required. @@ -56,12 +62,12 @@ func (c *ClientEncryptionOptions) SetTLSConfig(tlsOpts map[string]*tls.Config) * // to the KMS provider. The input map should contain a mapping from each KMS provider to a document containing the necessary // options, as follows: // -// { -// "kmip": { -// "tlsCertificateKeyFile": "foo.pem", -// "tlsCAFile": "fooCA.pem" -// } -// } +// { +// "kmip": { +// "tlsCertificateKeyFile": "foo.pem", +// "tlsCAFile": "fooCA.pem" +// } +// } // // Currently, the following TLS options are supported: // @@ -132,6 +138,9 @@ func MergeClientEncryptionOptions(opts ...*ClientEncryptionOptions) *ClientEncry if opt.TLSConfig != nil { ceo.TLSConfig = opt.TLSConfig } + if opt.HTTPClient != nil { + ceo.HTTPClient = opt.HTTPClient + } } return ceo diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go index 742a4da9b..4355b2f30 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go @@ -16,6 +16,7 @@ import ( "fmt" "io/ioutil" "net" + "net/http" "strings" "time" @@ -104,6 +105,7 @@ type ClientOptions struct { DisableOCSPEndpointCheck *bool HeartbeatInterval *time.Duration Hosts []string + HTTPClient *http.Client LoadBalanced *bool LocalThreshold *time.Duration MaxConnIdleTime *time.Duration @@ -162,7 +164,9 @@ type ClientOptions struct { // Client creates a new ClientOptions instance. func Client() *ClientOptions { - return new(ClientOptions) + return &ClientOptions{ + HTTPClient: internal.DefaultHTTPClient, + } } // Validate validates the client options. This method will return the first error found. @@ -204,7 +208,7 @@ func (c *ClientOptions) validate() error { if c.ReplicaSet != nil { return internal.ErrLoadBalancedWithReplicaSet } - if c.Direct != nil { + if c.Direct != nil && *c.Direct { return internal.ErrLoadBalancedWithDirectConnection } } @@ -728,9 +732,9 @@ func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions { // be honored if there is no deadline on the operation Context. Timeout can also be set through the "timeoutMS" URI option // (e.g. "timeoutMS=1000"). The default value is nil, meaning operations do not inherit a timeout from the Client. // -// If any Timeout is set (even 0) on the Client, the values of MaxTime on operations, TransactionOptions.MaxCommitTime and -// SessionOptions.DefaultMaxCommitTime will be ignored. Setting Timeout and ClientOptions.SocketTimeout or WriteConcern.wTimeout -// will result in undefined behavior. +// If any Timeout is set (even 0) on the Client, the values of MaxTime on operation options, TransactionOptions.MaxCommitTime and +// SessionOptions.DefaultMaxCommitTime will be ignored. Setting Timeout and SocketTimeout or WriteConcern.wTimeout will result +// in undefined behavior. // // NOTE(benjirewis): SetTimeout represents unstable, provisional API. The behavior of the driver when a Timeout is specified is // subject to change. @@ -767,6 +771,14 @@ func (c *ClientOptions) SetTLSConfig(cfg *tls.Config) *ClientOptions { return c } +// SetHTTPClient specifies the http.Client to be used for any HTTP requests. +// +// This should only be used to set custom HTTP client configurations. By default, the connection will use an internal.DefaultHTTPClient. +func (c *ClientOptions) SetHTTPClient(client *http.Client) *ClientOptions { + c.HTTPClient = client + return c +} + // SetWriteConcern specifies the write concern to use to for write operations. This can also be set through the following // URI options: // @@ -889,6 +901,9 @@ func MergeClientOptions(opts ...*ClientOptions) *ClientOptions { if len(opt.Hosts) > 0 { c.Hosts = opt.Hosts } + if opt.HTTPClient != nil { + c.HTTPClient = opt.HTTPClient + } if opt.LoadBalanced != nil { c.LoadBalanced = opt.LoadBalanced } diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go index 648d9714e..059805a6a 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/datakeyoptions.go @@ -29,30 +29,36 @@ func DataKey() *DataKeyOptions { // "endpoint" or "keyVaultEndpoint" must be a host name with an optional port number (e.g. "foo.com" or "foo.com:443"). // // When using AWS, the document must have the format: -// { -// region: , -// key: , // The Amazon Resource Name (ARN) to the AWS customer master key (CMK). -// endpoint: Optional // An alternate host identifier to send KMS requests to. -// } +// +// { +// region: , +// key: , // The Amazon Resource Name (ARN) to the AWS customer master key (CMK). +// endpoint: Optional // An alternate host identifier to send KMS requests to. +// } +// // If unset, the "endpoint" defaults to "kms..amazonaws.com". // // When using Azure, the document must have the format: -// { -// keyVaultEndpoint: , // A host identifier to send KMS requests to. -// keyName: , -// keyVersion: Optional // A specific version of the named key. -// } +// +// { +// keyVaultEndpoint: , // A host identifier to send KMS requests to. +// keyName: , +// keyVersion: Optional // A specific version of the named key. +// } +// // If unset, "keyVersion" defaults to the key's primary version. // // When using GCP, the document must have the format: -// { -// projectId: , -// location: , -// keyRing: , -// keyName: , -// keyVersion: Optional, // A specific version of the named key. -// endpoint: Optional // An alternate host identifier to send KMS requests to. -// } +// +// { +// projectId: , +// location: , +// keyRing: , +// keyName: , +// keyVersion: Optional, // A specific version of the named key. +// endpoint: Optional // An alternate host identifier to send KMS requests to. +// } +// // If unset, "keyVersion" defaults to the key's primary version and "endpoint" defaults to "cloudkms.googleapis.com". func (dk *DataKeyOptions) SetMasterKey(masterKey interface{}) *DataKeyOptions { dk.MasterKey = masterKey diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/session.go b/vendor/go.mongodb.org/mongo-driver/mongo/session.go index 1c8b535c5..37d5b7576 100644 --- a/vendor/go.mongodb.org/mongo-driver/mongo/session.go +++ b/vendor/go.mongodb.org/mongo-driver/mongo/session.go @@ -206,11 +206,27 @@ func (s *sessionImpl) WithTransaction(ctx context.Context, fn func(sessCtx Sessi return res, err } + // Check if callback intentionally aborted and, if so, return immediately + // with no error. err = s.clientSession.CheckAbortTransaction() if err != nil { return res, nil } + // If context has errored, run AbortTransaction and return, as the CommitLoop + // has no chance of succeeding. + // + // Aborting after a failed CommitTransaction is dangerous. Failed transaction + // commits may unpin the session server-side, and subsequent transaction aborts + // may run on a new mongos which could end up with commit and abort being executed + // simultaneously. + if ctx.Err() != nil { + // Wrap the user-provided Context in a new one that behaves like context.Background() for deadlines and + // cancellations, but forwards Value requests to the original one. + _ = s.AbortTransaction(internal.NewBackgroundContext(ctx)) + return nil, ctx.Err() + } + CommitLoop: for { err = s.CommitTransaction(ctx) @@ -308,10 +324,7 @@ func (s *sessionImpl) CommitTransaction(ctx context.Context) error { Session(s.clientSession).ClusterClock(s.client.clock).Database("admin").Deployment(s.deployment). WriteConcern(s.clientSession.CurrentWc).ServerSelector(selector).Retry(driver.RetryOncePerCommand). CommandMonitor(s.client.monitor).RecoveryToken(bsoncore.Document(s.clientSession.RecoveryToken)). - ServerAPI(s.client.serverAPI) - if s.clientSession.CurrentMct != nil { - op.MaxTimeMS(int64(*s.clientSession.CurrentMct / time.Millisecond)) - } + ServerAPI(s.client.serverAPI).MaxTime(s.clientSession.CurrentMct) err = op.Execute(ctx) // Return error without updating transaction state if it is a timeout, as the transaction has not diff --git a/vendor/go.mongodb.org/mongo-driver/version/version.go b/vendor/go.mongodb.org/mongo-driver/version/version.go index 0ca08359d..e42bd4d89 100644 --- a/vendor/go.mongodb.org/mongo-driver/version/version.go +++ b/vendor/go.mongodb.org/mongo-driver/version/version.go @@ -8,4 +8,4 @@ package version // import "go.mongodb.org/mongo-driver/version" // Driver is the current version of the driver. -var Driver = "v1.10.2" +var Driver = "v1.11.0" diff --git a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go index 6c858a010..e35bd0cd9 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go +++ b/vendor/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/document_sequence.go @@ -96,8 +96,8 @@ func (ds *DocumentSequence) Empty() bool { } } -//ResetIterator resets the iteration point for the Next method to the beginning of the document -//sequence. +// ResetIterator resets the iteration point for the Next method to the beginning of the document +// sequence. func (ds *DocumentSequence) ResetIterator() { if ds == nil { return diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/auth.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/auth.go index d45dda61b..6eeaf0ee0 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/auth.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/auth.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "net/http" "go.mongodb.org/mongo-driver/mongo/address" "go.mongodb.org/mongo-driver/mongo/description" @@ -60,6 +61,7 @@ type HandshakeOptions struct { ClusterClock *session.ClusterClock ServerAPI *driver.ServerAPIOptions LoadBalanced bool + HTTPClient *http.Client } type authHandshaker struct { @@ -130,6 +132,7 @@ func (ah *authHandshaker) FinishHandshake(ctx context.Context, conn driver.Conne ClusterClock: ah.options.ClusterClock, HandshakeInfo: ah.handshakeInfo, ServerAPI: ah.options.ServerAPI, + HTTPClient: ah.options.HTTPClient, } if err := ah.authenticate(ctx, cfg); err != nil { @@ -174,6 +177,7 @@ type Config struct { ClusterClock *session.ClusterClock HandshakeInfo driver.HandshakeInformation ServerAPI *driver.ServerAPIOptions + HTTPClient *http.Client } // Authenticator handles authenticating a connection. diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/aws_conv.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/aws_conv.go index eb0032ce3..8509abfbd 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/aws_conv.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/aws_conv.go @@ -36,12 +36,13 @@ const ( ) type awsConversation struct { - state clientState - valid bool - nonce []byte - username string - password string - token string + state clientState + valid bool + nonce []byte + username string + password string + token string + httpClient *http.Client } type serverMessage struct { @@ -147,14 +148,14 @@ func (ac *awsConversation) validateAndMakeCredentials() (*awsv4.StaticProvider, return nil, nil } -func executeAWSHTTPRequest(req *http.Request) ([]byte, error) { +func executeAWSHTTPRequest(httpClient *http.Client, req *http.Request) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), defaultHTTPTimeout) defer cancel() - resp, err := http.DefaultClient.Do(req.WithContext(ctx)) + resp, err := httpClient.Do(req.WithContext(ctx)) if err != nil { return nil, err } - defer func() { _ = resp.Body.Close() }() + defer resp.Body.Close() return ioutil.ReadAll(resp.Body) } @@ -167,7 +168,7 @@ func (ac *awsConversation) getEC2Credentials() (*awsv4.StaticProvider, error) { } req.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "30") - token, err := executeAWSHTTPRequest(req) + token, err := executeAWSHTTPRequest(ac.httpClient, req) if err != nil { return nil, err } @@ -183,7 +184,7 @@ func (ac *awsConversation) getEC2Credentials() (*awsv4.StaticProvider, error) { } req.Header.Set("X-aws-ec2-metadata-token", tokenStr) - role, err := executeAWSHTTPRequest(req) + role, err := executeAWSHTTPRequest(ac.httpClient, req) if err != nil { return nil, err } @@ -198,7 +199,7 @@ func (ac *awsConversation) getEC2Credentials() (*awsv4.StaticProvider, error) { return nil, err } req.Header.Set("X-aws-ec2-metadata-token", tokenStr) - creds, err := executeAWSHTTPRequest(req) + creds, err := executeAWSHTTPRequest(ac.httpClient, req) if err != nil { return nil, err } @@ -242,7 +243,7 @@ func (ac *awsConversation) getCredentials() (*awsv4.StaticProvider, error) { return nil, err } - body, err := executeAWSHTTPRequest(req) + body, err := executeAWSHTTPRequest(ac.httpClient, req) if err != nil { return nil, err } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/mongodbaws.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/mongodbaws.go index 8b81865e5..8982f04da 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/mongodbaws.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/auth/mongodbaws.go @@ -8,6 +8,7 @@ package auth import ( "context" + "errors" ) // MongoDBAWS is the mechanism name for MongoDBAWS. @@ -35,11 +36,16 @@ type MongoDBAWSAuthenticator struct { // Auth authenticates the connection. func (a *MongoDBAWSAuthenticator) Auth(ctx context.Context, cfg *Config) error { + httpClient := cfg.HTTPClient + if httpClient == nil { + return errors.New("cfg.HTTPClient must not be nil") + } adapter := &awsSaslAdapter{ conversation: &awsConversation{ - username: a.username, - password: a.password, - token: a.sessionToken, + username: a.username, + password: a.password, + token: a.sessionToken, + httpClient: httpClient, }, } err := ConductSaslConversation(ctx, cfg, a.source, adapter) diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/batch_cursor.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/batch_cursor.go index fda3e313f..032bbeb90 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/batch_cursor.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/batch_cursor.go @@ -11,10 +11,10 @@ import ( "errors" "fmt" "strings" - "time" "go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/event" + "go.mongodb.org/mongo-driver/internal" "go.mongodb.org/mongo-driver/mongo/description" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" "go.mongodb.org/mongo-driver/x/mongo/driver/session" @@ -305,7 +305,7 @@ func (bc *BatchCursor) KillCursor(ctx context.Context) error { Legacy: LegacyKillCursors, CommandMonitor: bc.cmdMonitor, ServerAPI: bc.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } func (bc *BatchCursor) getMore(ctx context.Context) { @@ -384,7 +384,7 @@ func (bc *BatchCursor) getMore(ctx context.Context) { CommandMonitor: bc.cmdMonitor, Crypt: bc.crypt, ServerAPI: bc.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) // Once the cursor has been drained, we can unpin the connection if one is currently pinned. if bc.id == 0 { @@ -455,14 +455,9 @@ func (lbcd *loadBalancedCursorDeployment) Connection(_ context.Context) (Connect return lbcd.conn, nil } -// MinRTT always returns 0. It implements the driver.Server interface. -func (lbcd *loadBalancedCursorDeployment) MinRTT() time.Duration { - return 0 -} - -// RTT90 always returns 0. It implements the driver.Server interface. -func (lbcd *loadBalancedCursorDeployment) RTT90() time.Duration { - return 0 +// RTTMonitor implements the driver.Server interface. +func (lbcd *loadBalancedCursorDeployment) RTTMonitor() RTTMonitor { + return &internal.ZeroRTTMonitor{} } func (lbcd *loadBalancedCursorDeployment) ProcessError(err error, conn Connection) ProcessErrorResult { diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/connstring/connstring.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/connstring/connstring.go index ac6a33c8f..6f03a5857 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/connstring/connstring.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/connstring/connstring.go @@ -494,7 +494,7 @@ func (p *parser) validateAuth() error { return fmt.Errorf("username required for GSSAPI") } for k := range p.AuthMechanismProperties { - if k != "SERVICE_NAME" && k != "CANONICALIZE_HOST_NAME" && k != "SERVICE_REALM" { + if k != "SERVICE_NAME" && k != "CANONICALIZE_HOST_NAME" && k != "SERVICE_REALM" && k != "SERVICE_HOST" { return fmt.Errorf("invalid auth property for GSSAPI") } } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/crypt.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/crypt.go index a203ed29b..cd918fc46 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/crypt.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/crypt.go @@ -9,12 +9,17 @@ package driver import ( "context" "crypto/tls" + "encoding/json" "fmt" "io" + "io/ioutil" + "net/http" + "os" "strings" "time" "go.mongodb.org/mongo-driver/bson/bsontype" + "go.mongodb.org/mongo-driver/internal" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt" "go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/options" @@ -41,6 +46,7 @@ type CryptOptions struct { KeyFn KeyRetrieverFn MarkFn MarkCommandFn TLSConfig map[string]*tls.Config + HTTPClient *http.Client BypassAutoEncryption bool BypassQueryAnalysis bool } @@ -78,20 +84,26 @@ type crypt struct { keyFn KeyRetrieverFn markFn MarkCommandFn tlsConfig map[string]*tls.Config + httpClient *http.Client bypassAutoEncryption bool } // NewCrypt creates a new Crypt instance configured with the given AutoEncryptionOptions. func NewCrypt(opts *CryptOptions) Crypt { - return &crypt{ + c := &crypt{ mongoCrypt: opts.MongoCrypt, collInfoFn: opts.CollInfoFn, keyFn: opts.KeyFn, markFn: opts.MarkFn, tlsConfig: opts.TLSConfig, + httpClient: opts.HTTPClient, bypassAutoEncryption: opts.BypassAutoEncryption, } + if c.httpClient == nil { + c.httpClient = internal.DefaultHTTPClient + } + return c } // Encrypt encrypts the given command. @@ -226,6 +238,9 @@ func (c *crypt) DecryptExplicit(ctx context.Context, subtype byte, data []byte) // Close cleans up any resources associated with the Crypt instance. func (c *crypt) Close() { c.mongoCrypt.Close() + if c.httpClient == internal.DefaultHTTPClient { + internal.CloseIdleHTTPConnections(c.httpClient) + } } func (c *crypt) BypassAutoEncryption() bool { @@ -249,6 +264,8 @@ func (c *crypt) executeStateMachine(ctx context.Context, cryptCtx *mongocrypt.Co return cryptCtx.Finish() case mongocrypt.Done: return nil, nil + case mongocrypt.NeedKmsCredentials: + err = c.provideKmsProviders(ctx, cryptCtx) default: return nil, fmt.Errorf("invalid Crypt state: %v", state) } @@ -382,3 +399,75 @@ func (c *crypt) decryptKey(kmsCtx *mongocrypt.KmsContext) error { } } } + +// needsKmsProvider returns true if provider was initially set to an empty document. +// An empty document signals the driver to fetch credentials. +func needsKmsProvider(kmsProviders bsoncore.Document, provider string) bool { + val, err := kmsProviders.LookupErr(provider) + if err != nil { + // KMS provider is not configured. + return false + } + doc, ok := val.DocumentOK() + // KMS provider is an empty document. + return ok && len(doc) == 5 +} + +func getGCPAccessToken(ctx context.Context, httpClient *http.Client) (string, error) { + metadataHost := "metadata.google.internal" + if envhost := os.Getenv("GCE_METADATA_HOST"); envhost != "" { + metadataHost = envhost + } + url := fmt.Sprintf("http://%s/computeMetadata/v1/instance/service-accounts/default/token", metadataHost) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return "", internal.WrapErrorf(err, "unable to retrieve GCP credentials") + } + req.Header.Set("Metadata-Flavor", "Google") + resp, err := httpClient.Do(req.WithContext(ctx)) + if err != nil { + return "", internal.WrapErrorf(err, "unable to retrieve GCP credentials") + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", internal.WrapErrorf(err, "unable to retrieve GCP credentials: error reading response body") + } + if resp.StatusCode != http.StatusOK { + return "", internal.WrapErrorf(err, "unable to retrieve GCP credentials: expected StatusCode 200, got StatusCode: %v. Response body: %s", resp.StatusCode, body) + } + var tokenResponse struct { + AccessToken string `json:"access_token"` + } + // Attempt to read body as JSON + err = json.Unmarshal(body, &tokenResponse) + if err != nil { + return "", internal.WrapErrorf(err, "unable to retrieve GCP credentials: error reading body JSON. Response body: %s", body) + } + if tokenResponse.AccessToken == "" { + return "", fmt.Errorf("unable to retrieve GCP credentials: got unexpected empty accessToken from GCP Metadata Server. Response body: %s", body) + } + return tokenResponse.AccessToken, nil +} + +func (c *crypt) provideKmsProviders(ctx context.Context, cryptCtx *mongocrypt.Context) error { + kmsProviders := c.mongoCrypt.GetKmsProviders() + builder := bsoncore.NewDocumentBuilder() + + if needsKmsProvider(kmsProviders, "gcp") { + // "gcp" KMS provider is an empty document. + // Attempt to fetch from GCP Instance Metadata server. + { + token, err := getGCPAccessToken(ctx, c.httpClient) + if err != nil { + return err + } + builder.StartDocument("gcp"). + AppendString("accessToken", token). + FinishDocument() + + } + } + + return cryptCtx.ProvideKmsProviders(builder.Build()) +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/driver.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/driver.go index db5788aaf..2ca9ab38b 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/driver.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/driver.go @@ -10,6 +10,7 @@ import ( "context" "time" + "go.mongodb.org/mongo-driver/internal" "go.mongodb.org/mongo-driver/mongo/address" "go.mongodb.org/mongo-driver/mongo/description" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" @@ -51,11 +52,8 @@ type Subscriber interface { type Server interface { Connection(context.Context) (Connection, error) - // MinRTT returns the minimum round-trip time to the server observed over the window period. - MinRTT() time.Duration - - // RTT90 returns the 90th percentile round-trip time to the server observed over the window period. - RTT90() time.Duration + // RTTMonitor returns the round-trip time monitor associated with this server. + RTTMonitor() RTTMonitor } // Connection represents a connection to a MongoDB server. @@ -75,6 +73,23 @@ type Connection interface { Stale() bool } +// RTTMonitor represents a round-trip-time monitor. +type RTTMonitor interface { + // EWMA returns the exponentially weighted moving average observed round-trip time. + EWMA() time.Duration + + // Min returns the minimum observed round-trip time over the window period. + Min() time.Duration + + // P90 returns the 90th percentile observed round-trip time over the window period. + P90() time.Duration + + // Stats returns stringified stats of the current state of the monitor. + Stats() string +} + +var _ RTTMonitor = &internal.ZeroRTTMonitor{} + // PinnedConnection represents a Connection that can be pinned by one or more cursors or transactions. Implementations // of this interface should maintain the following invariants: // @@ -212,14 +227,9 @@ func (ssd SingleConnectionDeployment) Connection(context.Context) (Connection, e return ssd.C, nil } -// MinRTT always returns 0. It implements the driver.Server interface. -func (ssd SingleConnectionDeployment) MinRTT() time.Duration { - return 0 -} - -// RTT90 always returns 0. It implements the driver.Server interface. -func (ssd SingleConnectionDeployment) RTT90() time.Duration { - return 0 +// RTTMonitor implements the driver.Server interface. +func (ssd SingleConnectionDeployment) RTTMonitor() RTTMonitor { + return &internal.ZeroRTTMonitor{} } // TODO(GODRIVER-617): We can likely use 1 type for both the Type and the RetryMode by using 2 bits for the mode and 1 @@ -241,15 +251,17 @@ const ( // RetryMode specifies the way that retries are handled for retryable operations. type RetryMode uint -// These are the modes available for retrying. +// These are the modes available for retrying. Note that if Timeout is specified on the Client, the +// operation will automatically retry as many times as possible within the context's deadline +// unless RetryNone is used. const ( // RetryNone disables retrying. RetryNone RetryMode = iota - // RetryOnce will enable retrying the entire operation once. + // RetryOnce will enable retrying the entire operation once if Timeout is not specified. RetryOnce - // RetryOncePerCommand will enable retrying each command associated with an operation. For - // example, if an insert is batch split into 4 commands then each of those commands is eligible - // for one retry. + // RetryOncePerCommand will enable retrying each command associated with an operation if Timeout + // is not specified. For example, if an insert is batch split into 4 commands then each of + // those commands is eligible for one retry. RetryOncePerCommand // RetryContext will enable retrying until the context.Context's deadline is exceeded or it is // cancelled. diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/errors.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/errors.go index 20a7de55d..cb56b84f5 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/errors.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/errors.go @@ -37,6 +37,8 @@ var ( NetworkError = "NetworkError" // RetryableWriteError is an error lable for retryable write errors. RetryableWriteError = "RetryableWriteError" + // NoWritesPerformed is an error label indicated that no writes were performed for an operation. + NoWritesPerformed = "NoWritesPerformed" // ErrCursorNotFound is the cursor not found error for legacy find operations. ErrCursorNotFound = errors.New("cursor not found") // ErrUnacknowledgedWrite is returned from functions that have an unacknowledged @@ -48,6 +50,8 @@ var ( // ErrDeadlineWouldBeExceeded is returned when a Timeout set on an operation would be exceeded // if the operation were sent to the server. ErrDeadlineWouldBeExceeded = errors.New("operation not sent to server, as Timeout would be exceeded") + // ErrNegativeMaxTime is returned when MaxTime on an operation is a negative value. + ErrNegativeMaxTime = errors.New("a negative value was provided for MaxTime on an operation") ) // QueryFailureError is an error representing a command failure as a document. @@ -130,6 +134,18 @@ func (wce WriteCommandError) Retryable(wireVersion *description.VersionRange) bo return (*wce.WriteConcernError).Retryable() } +// HasErrorLabel returns true if the error contains the specified label. +func (wce WriteCommandError) HasErrorLabel(label string) bool { + if wce.Labels != nil { + for _, l := range wce.Labels { + if l == label { + return true + } + } + } + return false +} + // WriteConcernError is a write concern failure that occurred as a result of a // write operation. type WriteConcernError struct { diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt.go index 214d7c47b..a6a60c730 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt.go @@ -26,7 +26,8 @@ import ( ) type MongoCrypt struct { - wrapped *C.mongocrypt_t + wrapped *C.mongocrypt_t + kmsProviders bsoncore.Document } // Version returns the version string for the loaded libmongocrypt, or an empty string @@ -44,7 +45,8 @@ func NewMongoCrypt(opts *options.MongoCryptOptions) (*MongoCrypt, error) { return nil, errors.New("could not create new mongocrypt object") } crypt := &MongoCrypt{ - wrapped: wrapped, + wrapped: wrapped, + kmsProviders: opts.KmsProviders, } // set options in mongocrypt @@ -76,6 +78,8 @@ func NewMongoCrypt(opts *options.MongoCryptOptions) (*MongoCrypt, error) { } } + C.mongocrypt_setopt_use_need_kms_credentials_state(crypt.wrapped) + // initialize handle if !C.mongocrypt_init(crypt.wrapped) { return nil, crypt.createErrorFromStatus() @@ -405,3 +409,8 @@ func (m *MongoCrypt) createErrorFromStatus() error { C.mongocrypt_status(m.wrapped, status) return errorFromStatus(status) } + +// GetKmsProviders returns the originally configured KMS providers. +func (m *MongoCrypt) GetKmsProviders() bsoncore.Document { + return m.kmsProviders +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context.go index a53801965..04e98d01c 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context.go @@ -102,3 +102,14 @@ func (c *Context) createErrorFromStatus() error { C.mongocrypt_ctx_status(c.wrapped, status) return errorFromStatus(status) } + +// ProvideKmsProviders provides the KMS providers when in the NeedKmsCredentials state. +func (c *Context) ProvideKmsProviders(kmsProviders bsoncore.Document) error { + kmsProvidersBinary := newBinaryFromBytes(kmsProviders) + defer kmsProvidersBinary.close() + + if ok := C.mongocrypt_ctx_provide_kms_providers(c.wrapped, kmsProvidersBinary.wrapped); !ok { + return c.createErrorFromStatus() + } + return nil +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context_not_enabled.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context_not_enabled.go index 624888a2f..2e2776914 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context_not_enabled.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_context_not_enabled.go @@ -55,3 +55,8 @@ func (c *Context) Finish() (bsoncore.Document, error) { func (c *Context) Close() { panic(cseNotSupportedMsg) } + +// ProvideKmsProviders provides the KMS providers when in the NeedKmsCredentials state. +func (c *Context) ProvideKmsProviders(kmsProviders bsoncore.Document) error { + panic(cseNotSupportedMsg) +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_not_enabled.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_not_enabled.go index 45e16988c..a333dc536 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_not_enabled.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/mongocrypt_not_enabled.go @@ -76,3 +76,8 @@ func (m *MongoCrypt) CryptSharedLibVersionString() string { func (m *MongoCrypt) Close() { panic(cseNotSupportedMsg) } + +// GetKmsProviders returns the originally configured KMS providers. +func (m *MongoCrypt) GetKmsProviders() bsoncore.Document { + panic(cseNotSupportedMsg) +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/state.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/state.go index c745088bd..60546160c 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/state.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/mongocrypt/state.go @@ -10,14 +10,16 @@ package mongocrypt type State int // These constants are valid values for the State type. +// The values must match the values defined in the mongocrypt_ctx_state_t enum in libmongocrypt. const ( - StateError State = iota - NeedMongoCollInfo - NeedMongoMarkings - NeedMongoKeys - NeedKms - Ready - Done + StateError State = 0 + NeedMongoCollInfo State = 1 + NeedMongoMarkings State = 2 + NeedMongoKeys State = 3 + NeedKms State = 4 + Ready State = 5 + Done State = 6 + NeedKmsCredentials State = 7 ) // String implements the Stringer interface. @@ -37,6 +39,8 @@ func (s State) String() string { return "Ready" case Done: return "Done" + case NeedKmsCredentials: + return "NeedKmsCredentials" default: return "Unknown State" } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/config.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/config.go index bee44fa57..4cb14e4d0 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/config.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/config.go @@ -10,7 +10,9 @@ import ( "crypto/x509" "errors" "fmt" + "net/http" + "go.mongodb.org/mongo-driver/internal" "golang.org/x/crypto/ocsp" ) @@ -20,12 +22,18 @@ type config struct { disableEndpointChecking bool ocspRequest *ocsp.Request ocspRequestBytes []byte + httpClient *http.Client } func newConfig(certChain []*x509.Certificate, opts *VerifyOptions) (config, error) { cfg := config{ cache: opts.Cache, disableEndpointChecking: opts.DisableEndpointChecking, + httpClient: opts.HTTPClient, + } + + if cfg.httpClient == nil { + cfg.httpClient = internal.DefaultHTTPClient } if len(certChain) == 0 { diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go index ed625706b..0e7dbfe2d 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/ocsp.go @@ -240,7 +240,7 @@ func contactResponders(ctx context.Context, cfg config) *ResponseDetails { } request = request.WithContext(ctx) - httpResponse, err := http.DefaultClient.Do(request) + httpResponse, err := cfg.httpClient.Do(request) if err != nil { return nil } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/options.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/options.go index feaea5c29..281bf515b 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/options.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/ocsp/options.go @@ -6,8 +6,11 @@ package ocsp +import "net/http" + // VerifyOptions specifies options to configure OCSP verification. type VerifyOptions struct { Cache Cache DisableEndpointChecking bool + HTTPClient *http.Client } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation.go index 4ea80e755..6324e9511 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation.go @@ -13,6 +13,7 @@ import ( "fmt" "strconv" "strings" + "sync" "time" "go.mongodb.org/mongo-driver/bson" @@ -58,6 +59,11 @@ type RetryablePoolError interface { Retryable() bool } +// LabeledError is an error that can have error labels added to it. +type LabeledError interface { + HasErrorLabel(string) bool +} + // InvalidOperationError is returned from Validate and indicates that a required field is missing // from an instance of Operation. type InvalidOperationError struct{ MissingField string } @@ -185,6 +191,8 @@ type Operation struct { // RetryMode specifies how to retry. There are three modes that enable retry: RetryOnce, // RetryOncePerCommand, and RetryContext. For more information about what these modes do, please // refer to their definitions. Both RetryMode and Type must be set for retryability to be enabled. + // If Timeout is set on the Client, the operation will automatically retry as many times as + // possible unless RetryNone is used. RetryMode *RetryMode // Type specifies the kind of operation this is. There is only one mode that enables retry: Write. @@ -217,6 +225,9 @@ type Operation struct { // read preference will not be added to the command on wire versions < 13. IsOutputAggregate bool + // MaxTime specifies the maximum amount of time to allow the operation to run on the server. + MaxTime *time.Duration + // Timeout is the amount of time that this operation can execute before returning an error. The default value // nil, which means that the timeout of the operation's caller will be used. Timeout *time.Duration @@ -306,9 +317,17 @@ func (op Operation) Validate() error { return nil } -// Execute runs this operation. The scratch parameter will be used and overwritten (potentially many -// times), this should mainly be used to enable pooling of byte slices. -func (op Operation) Execute(ctx context.Context, scratch []byte) error { +var memoryPool = sync.Pool{ + New: func() interface{} { + // Start with 1kb buffers. + b := make([]byte, 1024) + // Return a pointer as the static analysis tool suggests. + return &b + }, +} + +// Execute runs this operation. +func (op Operation) Execute(ctx context.Context) error { err := op.Validate() if err != nil { return err @@ -352,14 +371,20 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { } } } + // If context is a Timeout context, automatically set retries to -1 (infinite) if retrying is + // enabled. + retryEnabled := op.RetryMode != nil && op.RetryMode.Enabled() + if internal.IsTimeoutContext(ctx) && retryEnabled { + retries = -1 + } var srvr Server var conn Connection var res bsoncore.Document var operationErr WriteCommandError var prevErr error + var prevIndefiniteErr error batching := op.Batches.Valid() - retryEnabled := op.RetryMode != nil && op.RetryMode.Enabled() retrySupported := false first := true currIndex := 0 @@ -369,6 +394,16 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { resetForRetry := func(err error) { retries-- prevErr = err + + // Set the previous indefinite error to be returned in any case where a retryable write error does not have a + // NoWritesPerfomed label (the definite case). + switch err := err.(type) { + case LabeledError: + if !err.HasErrorLabel(NoWritesPerformed) && err.HasErrorLabel(RetryableWriteError) { + prevIndefiniteErr = err.(error) + } + } + // If we got a connection, close it immediately to release pool resources for // subsequent retries. if conn != nil { @@ -379,6 +414,19 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { conn = nil } + wm := memoryPool.Get().(*[]byte) + defer func() { + // Proper usage of a sync.Pool requires each entry to have approximately the same memory + // cost. To obtain this property when the stored type contains a variably-sized buffer, + // we add a hard limit on the maximum buffer to place back in the pool. We limit the + // size to 16MiB because that's the maximum wire message size supported by MongoDB. + // + // Comment copied from https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/fmt/print.go;l=147 + if cap(*wm) > 16*1024*1024 { + return + } + memoryPool.Put(wm) + }() for { // If the server or connection are nil, try to select a new server and get a new connection. if srvr == nil || conn == nil { @@ -400,6 +448,18 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { return err } defer conn.Close() + + // Set the server if it has not already been set and the session type is implicit. This will + // limit the number of implicit sessions to no greater than an application's maxPoolSize + // (ignoring operations that hold on to the session like cursors). + if op.Client != nil && op.Client.Server == nil && op.Client.SessionType == session.Implicit { + if op.Client.Terminated { + return fmt.Errorf("unexpected nil session for a terminated implicit session") + } + if err := op.Client.SetServer(); err != nil { + return err + } + } } // Run steps that must only be run on the first attempt, but not again for retries. @@ -432,27 +492,20 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { first = false } - desc := description.SelectedServer{Server: conn.Description(), Kind: op.Deployment.Kind()} - scratch = scratch[:0] - if desc.WireVersion == nil || desc.WireVersion.Max < 4 { - switch op.Legacy { - case LegacyFind: - return op.legacyFind(ctx, scratch, srvr, conn, desc) - case LegacyGetMore: - return op.legacyGetMore(ctx, scratch, srvr, conn, desc) - case LegacyKillCursors: - return op.legacyKillCursors(ctx, scratch, srvr, conn, desc) - } + // Calculate maxTimeMS value to potentially be appended to the wire message. + maxTimeMS, err := op.calculateMaxTimeMS(ctx, srvr.RTTMonitor().P90(), srvr.RTTMonitor().Stats()) + if err != nil { + return err } - if desc.WireVersion == nil || desc.WireVersion.Max < 3 { - switch op.Legacy { - case LegacyListCollections: - return op.legacyListCollections(ctx, scratch, srvr, conn, desc) - case LegacyListIndexes: - return op.legacyListIndexes(ctx, scratch, srvr, conn, desc) - } + + // Set maxTimeMS to 0 if connected to mongocryptd to avoid appending the field. The final + // encrypted command may contain multiple maxTimeMS fields otherwise. + if conn.Description().IsCryptd { + maxTimeMS = 0 } + desc := description.SelectedServer{Server: conn.Description(), Kind: op.Deployment.Kind()} + if batching { targetBatchSize := desc.MaxDocumentSize maxDocSize := desc.MaxDocumentSize @@ -471,30 +524,8 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { } } - // Calculate value of 'maxTimeMS' field to potentially append to the wire message based on the current - // context's deadline and the 90th percentile RTT if the ctx is a Timeout Context. - var maxTimeMS uint64 - if internal.IsTimeoutContext(ctx) { - if deadline, ok := ctx.Deadline(); ok { - remainingTimeout := time.Until(deadline) - - maxTimeMSVal := int64(remainingTimeout/time.Millisecond) - - int64(srvr.RTT90()/time.Millisecond) - - // A maxTimeMS value <= 0 indicates that we are already at or past the Context's deadline. - if maxTimeMSVal <= 0 { - return internal.WrapErrorf(ErrDeadlineWouldBeExceeded, - "Context deadline has already been surpassed by %v", remainingTimeout) - } - maxTimeMS = uint64(maxTimeMSVal) - } - } - - // convert to wire message - if len(scratch) > 0 { - scratch = scratch[:0] - } - wm, startedInfo, err := op.createWireMessage(ctx, scratch, desc, maxTimeMS, conn) + var startedInfo startedInformation + *wm, startedInfo, err = op.createWireMessage(ctx, (*wm)[:0], desc, maxTimeMS, conn) if err != nil { return err } @@ -509,11 +540,14 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { op.publishStartedEvent(ctx, startedInfo) // get the moreToCome flag information before we compress - moreToCome := wiremessage.IsMsgMoreToCome(wm) + moreToCome := wiremessage.IsMsgMoreToCome(*wm) // compress wiremessage if allowed if compressor, ok := conn.(Compressor); ok && op.canCompress(startedInfo.cmdName) { - wm, err = compressor.CompressWireMessage(wm, nil) + b := memoryPool.Get().(*[]byte) + *b, err = compressor.CompressWireMessage(*wm, (*b)[:0]) + memoryPool.Put(wm) + wm = b if err != nil { return err } @@ -535,10 +569,10 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { if ctx.Err() != nil { err = ctx.Err() } else if deadline, ok := ctx.Deadline(); ok { - if internal.IsTimeoutContext(ctx) && time.Now().Add(srvr.RTT90()).After(deadline) { + if internal.IsTimeoutContext(ctx) && time.Now().Add(srvr.RTTMonitor().P90()).After(deadline) { err = internal.WrapErrorf(ErrDeadlineWouldBeExceeded, - "Remaining timeout %v applied from Timeout is less than 90th percentile RTT", time.Until(deadline)) - } else if time.Now().Add(srvr.MinRTT()).After(deadline) { + "remaining time %v until context deadline is less than 90th percentile RTT\n%v", time.Until(deadline), srvr.RTTMonitor().Stats()) + } else if time.Now().Add(srvr.RTTMonitor().Min()).After(deadline) { err = context.DeadlineExceeded } } @@ -550,7 +584,7 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { if moreToCome { roundTrip = op.moreToComeRoundTrip } - res, err = roundTrip(ctx, conn, wm) + res, *wm, err = roundTrip(ctx, conn, *wm) if ep, ok := srvr.(ErrorProcessor); ok { _ = ep.ProcessError(err, conn) @@ -592,6 +626,12 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { continue } + // If the error is no longer retryable and has the NoWritesPerformed label, then we should + // return the previous indefinite error. + if tt.HasErrorLabel(NoWritesPerformed) { + return prevIndefiniteErr + } + // If the operation isn't being retried, process the response if op.ProcessResponseFn != nil { info := ResponseInfo{ @@ -679,6 +719,12 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { continue } + // If the error is no longer retryable and has the NoWritesPerformed label, then we should + // return the previous indefinite error. + if tt.HasErrorLabel(NoWritesPerformed) { + return prevIndefiniteErr + } + // If the operation isn't being retried, process the response if op.ProcessResponseFn != nil { info := ResponseInfo{ @@ -731,11 +777,17 @@ func (op Operation) Execute(ctx context.Context, scratch []byte) error { // a retry, so increment the transaction number, reset the retries number, and don't set // server or connection to nil to continue using the same connection. if batching && len(op.Batches.Documents) > 0 { + // If retries are supported for the current operation on the current server description, + // the session isn't nil, and client retries are enabled, increment the txn number. + // Calling IncrementTxnNumber() for server descriptions or topologies that do not + // support retries (e.g. standalone topologies) will cause server errors. if retrySupported && op.Client != nil && op.RetryMode != nil { - if *op.RetryMode > RetryNone { + if op.RetryMode.Enabled() { op.Client.IncrementTxnNumber() } - if *op.RetryMode == RetryOncePerCommand { + // Reset the retries number for RetryOncePerCommand unless context is a Timeout context, in + // which case retries should remain as -1 (as many times as possible). + if *op.RetryMode == RetryOncePerCommand && !internal.IsTimeoutContext(ctx) { retries = 1 } } @@ -760,7 +812,6 @@ func (op Operation) retryable(desc description.Server) bool { return true } if retryWritesSupported(desc) && - desc.WireVersion != nil && desc.WireVersion.Max >= 6 && op.Client != nil && !(op.Client.TransactionInProgress() || op.Client.TransactionStarting()) && writeconcern.AckWrite(op.WriteConcern) { return true @@ -769,8 +820,7 @@ func (op Operation) retryable(desc description.Server) bool { if op.Client != nil && (op.Client.Committing || op.Client.Aborting) { return true } - if desc.WireVersion != nil && desc.WireVersion.Max >= 6 && - (op.Client == nil || !(op.Client.TransactionInProgress() || op.Client.TransactionStarting())) { + if op.Client == nil || !(op.Client.TransactionInProgress() || op.Client.TransactionStarting()) { return true } } @@ -779,21 +829,18 @@ func (op Operation) retryable(desc description.Server) bool { // roundTrip writes a wiremessage to the connection and then reads a wiremessage. The wm parameter // is reused when reading the wiremessage. -func (op Operation) roundTrip(ctx context.Context, conn Connection, wm []byte) ([]byte, error) { - err := conn.WriteWireMessage(ctx, wm) +func (op Operation) roundTrip(ctx context.Context, conn Connection, wm []byte) (result, pooledSlice []byte, err error) { + err = conn.WriteWireMessage(ctx, wm) if err != nil { - return nil, op.networkError(err) + return nil, wm, op.networkError(err) } - return op.readWireMessage(ctx, conn, wm) } -func (op Operation) readWireMessage(ctx context.Context, conn Connection, wm []byte) ([]byte, error) { - var err error - +func (op Operation) readWireMessage(ctx context.Context, conn Connection, wm []byte) (result, pooledSlice []byte, err error) { wm, err = conn.ReadWireMessage(ctx, wm[:0]) if err != nil { - return nil, op.networkError(err) + return nil, wm, op.networkError(err) } // If we're using a streamable connection, we set its streaming state based on the moreToCome flag in the server @@ -805,11 +852,14 @@ func (op Operation) readWireMessage(ctx context.Context, conn Connection, wm []b // decompress wiremessage wm, err = op.decompressWireMessage(wm) if err != nil { - return nil, err + return nil, wm, err } // decode - res, err := op.decodeResult(wm) + b, err := op.decodeResult(wm) + // Copy b to extend the lifetime. b may be a subslice of wm. wm will be added back to the memory pool and reused. + res := make([]byte, len(b)) + copy(res, b) // Update cluster/operation time and recovery tokens before handling the error to ensure we're properly updating // everything. op.updateClusterTimes(res) @@ -822,14 +872,14 @@ func (op Operation) readWireMessage(ctx context.Context, conn Connection, wm []b } if err != nil { - return res, err + return res, wm, err } // If there is no error, automatically attempt to decrypt all results if client side encryption is enabled. if op.Crypt != nil { - return op.Crypt.Decrypt(ctx, res) + res, err = op.Crypt.Decrypt(ctx, res) } - return res, nil + return res, wm, err } // networkError wraps the provided error in an Error with label "NetworkError" and, if a transaction @@ -855,15 +905,15 @@ func (op Operation) networkError(err error) error { // moreToComeRoundTrip writes a wiremessage to the provided connection. This is used when an OP_MSG is // being sent with the moreToCome bit set. -func (op *Operation) moreToComeRoundTrip(ctx context.Context, conn Connection, wm []byte) ([]byte, error) { - err := conn.WriteWireMessage(ctx, wm) +func (op *Operation) moreToComeRoundTrip(ctx context.Context, conn Connection, wm []byte) (result, pooledSlice []byte, err error) { + err = conn.WriteWireMessage(ctx, wm) if err != nil { if op.Client != nil { op.Client.MarkDirty() } err = Error{Message: err.Error(), Labels: []string{TransientTransactionError, NetworkError}, Wrapped: err} } - return bsoncore.BuildDocument(nil, bsoncore.AppendInt32Element(nil, "ok", 1)), err + return bsoncore.BuildDocument(nil, bsoncore.AppendInt32Element(nil, "ok", 1)), wm, err } // decompressWireMessage handles decompressing a wiremessage. If the wiremessage @@ -893,23 +943,37 @@ func (Operation) decompressWireMessage(wm []byte) ([]byte, error) { } compressedSize := length - 25 // header (16) + original opcode (4) + uncompressed size (4) + compressor ID (1) // return the original wiremessage - msg, rem, ok := wiremessage.ReadCompressedCompressedMessage(rem, compressedSize) + msg, _, ok := wiremessage.ReadCompressedCompressedMessage(rem, compressedSize) if !ok { return nil, errors.New("malformed OP_COMPRESSED: insufficient bytes for compressed wiremessage") } - header := make([]byte, 0, uncompressedSize+16) - header = wiremessage.AppendHeader(header, uncompressedSize+16, reqid, respto, opcode) + // Copy msg, which is a subslice of wm. wm will be used to store the return value of the decompressed message. + b := memoryPool.Get().(*[]byte) + msglen := len(msg) + if len(*b) < msglen { + *b = make([]byte, msglen) + } + copy(*b, msg) + defer func() { + memoryPool.Put(b) + }() + + if l := int(uncompressedSize) + 16; cap(wm) < l { + wm = make([]byte, 0, l) + } + wm = wiremessage.AppendHeader(wm[:0], uncompressedSize+16, reqid, respto, opcode) opts := CompressionOpts{ Compressor: compressorID, UncompressedSize: uncompressedSize, } - uncompressed, err := DecompressPayload(msg, opts) + uncompressed, err := DecompressPayload((*b)[0:msglen], opts) if err != nil { return nil, err } + wm = append(wm, uncompressed...) - return append(header, uncompressed...), nil + return wm, nil } func (op Operation) createWireMessage( @@ -1262,6 +1326,40 @@ func (op Operation) addClusterTime(dst []byte, desc description.SelectedServer) // return bsoncore.AppendDocumentElement(dst, "$clusterTime", clusterTime) } +// calculateMaxTimeMS calculates the value of the 'maxTimeMS' field to potentially append +// to the wire message based on the current context's deadline and the 90th percentile RTT +// if the ctx is a Timeout context. If the context is not a Timeout context, it uses the +// operation's MaxTimeMS if set. If no MaxTimeMS is set on the operation, and context is +// not a Timeout context, calculateMaxTimeMS returns 0. +func (op Operation) calculateMaxTimeMS(ctx context.Context, rtt90 time.Duration, rttStats string) (uint64, error) { + if internal.IsTimeoutContext(ctx) { + if deadline, ok := ctx.Deadline(); ok { + remainingTimeout := time.Until(deadline) + maxTime := remainingTimeout - rtt90 + + // Always round up to the next millisecond value so we never truncate the calculated + // maxTimeMS value (e.g. 400 microseconds evaluates to 1ms, not 0ms). + maxTimeMS := int64((maxTime + (time.Millisecond - 1)) / time.Millisecond) + if maxTimeMS <= 0 { + return 0, internal.WrapErrorf(ErrDeadlineWouldBeExceeded, + "remaining time %v until context deadline is less than or equal to 90th percentile RTT\n%v", + remainingTimeout, rttStats) + } + return uint64(maxTimeMS), nil + } + } else if op.MaxTime != nil { + // Users are not allowed to pass a negative value as MaxTime. A value of 0 would indicate + // no timeout and is allowed. + if *op.MaxTime < 0 { + return 0, ErrNegativeMaxTime + } + // Always round up to the next millisecond value so we never truncate the requested + // MaxTime value (e.g. 400 microseconds evaluates to 1ms, not 0ms). + return uint64((*op.MaxTime + (time.Millisecond - 1)) / time.Millisecond), nil + } + return 0, nil +} + // updateClusterTimes updates the cluster times for the session and cluster clock attached to this // operation. While the session's AdvanceClusterTime may return an error, this method does not // because an error being returned from this method will not be returned further up. @@ -1652,8 +1750,7 @@ func (op Operation) publishFinishedEvent(ctx context.Context, info finishedInfor res := bson.Raw{} // Only copy the reply for commands that are not security sensitive if !info.redacted { - res = make([]byte, len(info.response)) - copy(res, info.response) + res = bson.Raw(info.response) } successEvent := &event.CommandSucceededEvent{ Reply: res, diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/abort_transaction.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/abort_transaction.go index 608733b45..2bf0ec052 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/abort_transaction.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/abort_transaction.go @@ -64,7 +64,7 @@ func (at *AbortTransaction) Execute(ctx context.Context) error { Selector: at.selector, WriteConcern: at.writeConcern, ServerAPI: at.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/aggregate.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/aggregate.go index be311780d..4ea2263cb 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/aggregate.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/aggregate.go @@ -30,7 +30,7 @@ type Aggregate struct { collation bsoncore.Document comment *string hint bsoncore.Value - maxTimeMS *int64 + maxTime *time.Duration pipeline bsoncore.Document session *session.Client clock *session.ClusterClock @@ -109,8 +109,9 @@ func (a *Aggregate) Execute(ctx context.Context) error { MinimumWriteConcernWireVersion: 5, ServerAPI: a.serverAPI, IsOutputAggregate: a.hasOutputStage, + MaxTime: a.maxTime, Timeout: a.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -148,12 +149,6 @@ func (a *Aggregate) command(dst []byte, desc description.SelectedServer) ([]byte dst = bsoncore.AppendValueElement(dst, "hint", a.hint) } - - // Only append specified maxTimeMS if timeout is not also specified. - if a.maxTimeMS != nil && a.timeout == nil { - - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *a.maxTimeMS) - } if a.pipeline != nil { dst = bsoncore.AppendArrayElement(dst, "pipeline", a.pipeline) @@ -230,13 +225,13 @@ func (a *Aggregate) Hint(hint bsoncore.Value) *Aggregate { return a } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (a *Aggregate) MaxTimeMS(maxTimeMS int64) *Aggregate { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (a *Aggregate) MaxTime(maxTime *time.Duration) *Aggregate { if a == nil { a = new(Aggregate) } - a.maxTimeMS = &maxTimeMS + a.maxTime = maxTime return a } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/command.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/command.go index 517613923..574cb0314 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/command.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/command.go @@ -106,7 +106,7 @@ func (c *Command) Execute(ctx context.Context) error { Crypt: c.crypt, ServerAPI: c.serverAPI, Timeout: c.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } // Session sets the session for this operation. diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/commit_transaction.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/commit_transaction.go index 14ed7bcd8..ff2794a1f 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/commit_transaction.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/commit_transaction.go @@ -9,6 +9,7 @@ package operation import ( "context" "errors" + "time" "go.mongodb.org/mongo-driver/event" "go.mongodb.org/mongo-driver/mongo/description" @@ -20,7 +21,7 @@ import ( // CommitTransaction attempts to commit a transaction. type CommitTransaction struct { - maxTimeMS *int64 + maxTime *time.Duration recoveryToken bsoncore.Document session *session.Client clock *session.ClusterClock @@ -61,32 +62,30 @@ func (ct *CommitTransaction) Execute(ctx context.Context) error { Crypt: ct.crypt, Database: ct.database, Deployment: ct.deployment, + MaxTime: ct.maxTime, Selector: ct.selector, WriteConcern: ct.writeConcern, ServerAPI: ct.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } func (ct *CommitTransaction) command(dst []byte, desc description.SelectedServer) ([]byte, error) { dst = bsoncore.AppendInt32Element(dst, "commitTransaction", 1) - if ct.maxTimeMS != nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *ct.maxTimeMS) - } if ct.recoveryToken != nil { dst = bsoncore.AppendDocumentElement(dst, "recoveryToken", ct.recoveryToken) } return dst, nil } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (ct *CommitTransaction) MaxTimeMS(maxTimeMS int64) *CommitTransaction { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (ct *CommitTransaction) MaxTime(maxTime *time.Duration) *CommitTransaction { if ct == nil { ct = new(CommitTransaction) } - ct.maxTimeMS = &maxTimeMS + ct.maxTime = maxTime return ct } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go index 756bb5f62..7e605572d 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go @@ -24,7 +24,7 @@ import ( // Count represents a count operation. type Count struct { - maxTimeMS *int64 + maxTime *time.Duration query bsoncore.Document session *session.Client clock *session.ClusterClock @@ -120,12 +120,13 @@ func (c *Count) Execute(ctx context.Context) error { Crypt: c.crypt, Database: c.database, Deployment: c.deployment, + MaxTime: c.maxTime, ReadConcern: c.readConcern, ReadPreference: c.readPreference, Selector: c.selector, ServerAPI: c.serverAPI, Timeout: c.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) // Swallow error if NamespaceNotFound(26) is returned from aggregate on non-existent namespace if err != nil { @@ -142,24 +143,19 @@ func (c *Count) command(dst []byte, desc description.SelectedServer) ([]byte, er if c.query != nil { dst = bsoncore.AppendDocumentElement(dst, "query", c.query) } - - // Only append specified maxTimeMS if timeout is not also specified. - if c.maxTimeMS != nil && c.timeout == nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *c.maxTimeMS) - } if c.comment.Type != bsontype.Type(0) { dst = bsoncore.AppendValueElement(dst, "comment", c.comment) } return dst, nil } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (c *Count) MaxTimeMS(maxTimeMS int64) *Count { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (c *Count) MaxTime(maxTime *time.Duration) *Count { if c == nil { c = new(Count) } - c.maxTimeMS = &maxTimeMS + c.maxTime = maxTime return c } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/create.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/create.go index 445b38e06..c333c5a99 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/create.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/create.go @@ -77,7 +77,7 @@ func (c *Create) Execute(ctx context.Context) error { Selector: c.selector, WriteConcern: c.writeConcern, ServerAPI: c.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/createIndexes.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/createIndexes.go index b828bc186..70f7b5495 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/createIndexes.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/createIndexes.go @@ -25,7 +25,7 @@ import ( type CreateIndexes struct { commitQuorum bsoncore.Value indexes bsoncore.Document - maxTimeMS *int64 + maxTime *time.Duration session *session.Client clock *session.ClusterClock collection string @@ -112,11 +112,12 @@ func (ci *CreateIndexes) Execute(ctx context.Context) error { Crypt: ci.crypt, Database: ci.database, Deployment: ci.deployment, + MaxTime: ci.maxTime, Selector: ci.selector, WriteConcern: ci.writeConcern, ServerAPI: ci.serverAPI, Timeout: ci.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -131,10 +132,6 @@ func (ci *CreateIndexes) command(dst []byte, desc description.SelectedServer) ([ if ci.indexes != nil { dst = bsoncore.AppendArrayElement(dst, "indexes", ci.indexes) } - // Only append specified maxTimeMS if timeout is not also specified. - if ci.maxTimeMS != nil && ci.timeout == nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *ci.maxTimeMS) - } return dst, nil } @@ -160,13 +157,13 @@ func (ci *CreateIndexes) Indexes(indexes bsoncore.Document) *CreateIndexes { return ci } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (ci *CreateIndexes) MaxTimeMS(maxTimeMS int64) *CreateIndexes { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (ci *CreateIndexes) MaxTime(maxTime *time.Duration) *CreateIndexes { if ci == nil { ci = new(CreateIndexes) } - ci.maxTimeMS = &maxTimeMS + ci.maxTime = maxTime return ci } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/delete.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/delete.go index 79f7f1730..bb8359425 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/delete.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/delete.go @@ -111,7 +111,7 @@ func (d *Delete) Execute(ctx context.Context) error { WriteConcern: d.writeConcern, ServerAPI: d.serverAPI, Timeout: d.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/distinct.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/distinct.go index c4b16cd7e..af66654d6 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/distinct.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/distinct.go @@ -25,7 +25,7 @@ import ( type Distinct struct { collation bsoncore.Document key *string - maxTimeMS *int64 + maxTime *time.Duration query bsoncore.Document session *session.Client clock *session.ClusterClock @@ -99,12 +99,13 @@ func (d *Distinct) Execute(ctx context.Context) error { Crypt: d.crypt, Database: d.database, Deployment: d.deployment, + MaxTime: d.maxTime, ReadConcern: d.readConcern, ReadPreference: d.readPreference, Selector: d.selector, ServerAPI: d.serverAPI, Timeout: d.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -122,9 +123,6 @@ func (d *Distinct) command(dst []byte, desc description.SelectedServer) ([]byte, if d.key != nil { dst = bsoncore.AppendStringElement(dst, "key", *d.key) } - if d.maxTimeMS != nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *d.maxTimeMS) - } if d.query != nil { dst = bsoncore.AppendDocumentElement(dst, "query", d.query) } @@ -151,13 +149,13 @@ func (d *Distinct) Key(key string) *Distinct { return d } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (d *Distinct) MaxTimeMS(maxTimeMS int64) *Distinct { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (d *Distinct) MaxTime(maxTime *time.Duration) *Distinct { if d == nil { d = new(Distinct) } - d.maxTimeMS = &maxTimeMS + d.maxTime = maxTime return d } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_collection.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_collection.go index fab279dc9..2b65d4844 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_collection.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_collection.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "go.mongodb.org/mongo-driver/event" "go.mongodb.org/mongo-driver/mongo/description" @@ -32,6 +33,7 @@ type DropCollection struct { writeConcern *writeconcern.WriteConcern result DropCollectionResult serverAPI *driver.ServerAPIOptions + timeout *time.Duration } // DropCollectionResult represents a dropCollection result returned by the server. @@ -99,7 +101,8 @@ func (dc *DropCollection) Execute(ctx context.Context) error { Selector: dc.selector, WriteConcern: dc.writeConcern, ServerAPI: dc.serverAPI, - }.Execute(ctx, nil) + Timeout: dc.timeout, + }.Execute(ctx) } @@ -207,3 +210,13 @@ func (dc *DropCollection) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropCol dc.serverAPI = serverAPI return dc } + +// Timeout sets the timeout for this operation. +func (dc *DropCollection) Timeout(timeout *time.Duration) *DropCollection { + if dc == nil { + dc = new(DropCollection) + } + + dc.timeout = timeout + return dc +} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_database.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_database.go index be2220c6f..ae011e2ba 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_database.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_database.go @@ -53,7 +53,7 @@ func (dd *DropDatabase) Execute(ctx context.Context) error { Selector: dd.selector, WriteConcern: dd.writeConcern, ServerAPI: dd.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_indexes.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_indexes.go index 20ca3668b..2e8569021 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_indexes.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/drop_indexes.go @@ -23,7 +23,7 @@ import ( // DropIndexes performs an dropIndexes operation. type DropIndexes struct { index *string - maxTimeMS *int64 + maxTime *time.Duration session *session.Client clock *session.ClusterClock collection string @@ -94,11 +94,12 @@ func (di *DropIndexes) Execute(ctx context.Context) error { Crypt: di.crypt, Database: di.database, Deployment: di.deployment, + MaxTime: di.maxTime, Selector: di.selector, WriteConcern: di.writeConcern, ServerAPI: di.serverAPI, Timeout: di.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -107,15 +108,10 @@ func (di *DropIndexes) command(dst []byte, desc description.SelectedServer) ([]b if di.index != nil { dst = bsoncore.AppendStringElement(dst, "index", *di.index) } - // Only append specified maxTimeMS if timeout is not also specified. - if di.maxTimeMS != nil && di.timeout == nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *di.maxTimeMS) - } return dst, nil } // Index specifies the name of the index to drop. If '*' is specified, all indexes will be dropped. -// func (di *DropIndexes) Index(index string) *DropIndexes { if di == nil { di = new(DropIndexes) @@ -125,13 +121,13 @@ func (di *DropIndexes) Index(index string) *DropIndexes { return di } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (di *DropIndexes) MaxTimeMS(maxTimeMS int64) *DropIndexes { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (di *DropIndexes) MaxTime(maxTime *time.Duration) *DropIndexes { if di == nil { di = new(DropIndexes) } - di.maxTimeMS = &maxTimeMS + di.maxTime = maxTime return di } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/end_sessions.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/end_sessions.go index 8384fb2d7..644d19555 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/end_sessions.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/end_sessions.go @@ -59,7 +59,7 @@ func (es *EndSessions) Execute(ctx context.Context) error { Deployment: es.deployment, Selector: es.selector, ServerAPI: es.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find.go index 5ccbf9f91..6ccdfcae8 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find.go @@ -34,7 +34,7 @@ type Find struct { let bsoncore.Document limit *int64 max bsoncore.Document - maxTimeMS *int64 + maxTime *time.Duration min bsoncore.Document noCursorTimeout *bool oplogReplay *bool @@ -98,13 +98,14 @@ func (f *Find) Execute(ctx context.Context) error { Crypt: f.crypt, Database: f.database, Deployment: f.deployment, + MaxTime: f.maxTime, ReadConcern: f.readConcern, ReadPreference: f.readPreference, Selector: f.selector, Legacy: driver.LegacyFind, ServerAPI: f.serverAPI, Timeout: f.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -149,10 +150,6 @@ func (f *Find) command(dst []byte, desc description.SelectedServer) ([]byte, err if f.max != nil { dst = bsoncore.AppendDocumentElement(dst, "max", f.max) } - // Only append specified maxTimeMS if timeout is not also specified. - if f.maxTimeMS != nil && f.timeout == nil { - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *f.maxTimeMS) - } if f.min != nil { dst = bsoncore.AppendDocumentElement(dst, "min", f.min) } @@ -299,13 +296,13 @@ func (f *Find) Max(max bsoncore.Document) *Find { return f } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (f *Find) MaxTimeMS(maxTimeMS int64) *Find { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (f *Find) MaxTime(maxTime *time.Duration) *Find { if f == nil { f = new(Find) } - f.maxTimeMS = &maxTimeMS + f.maxTime = maxTime return f } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find_and_modify.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find_and_modify.go index deaabea31..7c4cb527b 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find_and_modify.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/find_and_modify.go @@ -29,7 +29,7 @@ type FindAndModify struct { collation bsoncore.Document comment bsoncore.Value fields bsoncore.Document - maxTimeMS *int64 + maxTime *time.Duration newDocument *bool query bsoncore.Document remove *bool @@ -137,12 +137,13 @@ func (fam *FindAndModify) Execute(ctx context.Context) error { CommandMonitor: fam.monitor, Database: fam.database, Deployment: fam.deployment, + MaxTime: fam.maxTime, Selector: fam.selector, WriteConcern: fam.writeConcern, Crypt: fam.crypt, ServerAPI: fam.serverAPI, Timeout: fam.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -173,12 +174,6 @@ func (fam *FindAndModify) command(dst []byte, desc description.SelectedServer) ( dst = bsoncore.AppendDocumentElement(dst, "fields", fam.fields) } - - // Only append specified maxTimeMS if timeout is not also specified. - if fam.maxTimeMS != nil && fam.timeout == nil { - - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *fam.maxTimeMS) - } if fam.newDocument != nil { dst = bsoncore.AppendBooleanElement(dst, "new", *fam.newDocument) @@ -269,13 +264,13 @@ func (fam *FindAndModify) Fields(fields bsoncore.Document) *FindAndModify { return fam } -// MaxTimeMS specifies the maximum amount of time to allow the operation to run. -func (fam *FindAndModify) MaxTimeMS(maxTimeMS int64) *FindAndModify { +// MaxTime specifies the maximum amount of time to allow the operation to run on the server. +func (fam *FindAndModify) MaxTime(maxTime *time.Duration) *FindAndModify { if fam == nil { fam = new(FindAndModify) } - fam.maxTimeMS = &maxTimeMS + fam.maxTime = maxTime return fam } @@ -310,7 +305,6 @@ func (fam *FindAndModify) Remove(remove bool) *FindAndModify { } // Sort determines which document the operation modifies if the query matches multiple documents.The first document matched by the sort order will be modified. -// func (fam *FindAndModify) Sort(sort bsoncore.Document) *FindAndModify { if fam == nil { fam = new(FindAndModify) diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/hello.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/hello.go index 5e75c08ee..e764c84b9 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/hello.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/hello.go @@ -194,12 +194,12 @@ func (h *Hello) Execute(ctx context.Context) error { return errors.New("a Hello must have a Deployment set before Execute can be called") } - return h.createOperation().Execute(ctx, nil) + return h.createOperation().Execute(ctx) } // StreamResponse gets the next streaming Hello response from the server. func (h *Hello) StreamResponse(ctx context.Context, conn driver.StreamerConnection) error { - return h.createOperation().ExecuteExhaust(ctx, conn, nil) + return h.createOperation().ExecuteExhaust(ctx, conn) } func (h *Hello) createOperation() driver.Operation { @@ -229,7 +229,7 @@ func (h *Hello) GetHandshakeInformation(ctx context.Context, _ address.Address, return nil }, ServerAPI: h.serverAPI, - }.Execute(ctx, nil) + }.Execute(ctx) if err != nil { return driver.HandshakeInformation{}, err } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/insert.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/insert.go index 9f62cba34..83ba5e6e1 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/insert.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/insert.go @@ -110,7 +110,7 @@ func (i *Insert) Execute(ctx context.Context) error { WriteConcern: i.writeConcern, ServerAPI: i.serverAPI, Timeout: i.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/listDatabases.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/listDatabases.go index f1b4aa05a..28f72dd12 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/listDatabases.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/listDatabases.go @@ -163,7 +163,7 @@ func (ld *ListDatabases) Execute(ctx context.Context) error { Crypt: ld.crypt, ServerAPI: ld.serverAPI, Timeout: ld.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_collections.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_collections.go index 594a27f6b..7118417f7 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_collections.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_collections.go @@ -88,7 +88,7 @@ func (lc *ListCollections) Execute(ctx context.Context) error { Legacy: driver.LegacyListCollections, ServerAPI: lc.serverAPI, Timeout: lc.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_indexes.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_indexes.go index 39e6f25cc..9e5901b99 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_indexes.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/list_indexes.go @@ -21,7 +21,7 @@ import ( // ListIndexes performs a listIndexes operation. type ListIndexes struct { batchSize *int32 - maxTimeMS *int64 + maxTime *time.Duration session *session.Client clock *session.ClusterClock collection string @@ -75,6 +75,7 @@ func (li *ListIndexes) Execute(ctx context.Context) error { CommandMonitor: li.monitor, Database: li.database, Deployment: li.deployment, + MaxTime: li.maxTime, Selector: li.selector, Crypt: li.crypt, Legacy: driver.LegacyListIndexes, @@ -82,7 +83,7 @@ func (li *ListIndexes) Execute(ctx context.Context) error { Type: driver.Read, ServerAPI: li.serverAPI, Timeout: li.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } @@ -94,12 +95,6 @@ func (li *ListIndexes) command(dst []byte, desc description.SelectedServer) ([]b cursorDoc = bsoncore.AppendInt32Element(cursorDoc, "batchSize", *li.batchSize) } - - // Only append specified maxTimeMS if timeout is not also specified. - if li.maxTimeMS != nil && li.timeout == nil { - - dst = bsoncore.AppendInt64Element(dst, "maxTimeMS", *li.maxTimeMS) - } cursorDoc, _ = bsoncore.AppendDocumentEnd(cursorDoc, cursorIdx) dst = bsoncore.AppendDocumentElement(dst, "cursor", cursorDoc) @@ -116,13 +111,13 @@ func (li *ListIndexes) BatchSize(batchSize int32) *ListIndexes { return li } -// MaxTimeMS specifies the maximum amount of time to allow the query to run. -func (li *ListIndexes) MaxTimeMS(maxTimeMS int64) *ListIndexes { +// MaxTime specifies the maximum amount of time to allow the query to run on the server. +func (li *ListIndexes) MaxTime(maxTime *time.Duration) *ListIndexes { if li == nil { li = new(ListIndexes) } - li.maxTimeMS = &maxTimeMS + li.maxTime = maxTime return li } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/update.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/update.go index 8ea133e23..816b3709b 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/update.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation/update.go @@ -162,7 +162,7 @@ func (u *Update) Execute(ctx context.Context) error { Crypt: u.crypt, ServerAPI: u.serverAPI, Timeout: u.timeout, - }.Execute(ctx, nil) + }.Execute(ctx) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_exhaust.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_exhaust.go index eb15dc95e..df7856b89 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_exhaust.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_exhaust.go @@ -13,13 +13,18 @@ import ( // ExecuteExhaust reads a response from the provided StreamerConnection. This will error if the connection's // CurrentlyStreaming function returns false. -func (op Operation) ExecuteExhaust(ctx context.Context, conn StreamerConnection, scratch []byte) error { +func (op Operation) ExecuteExhaust(ctx context.Context, conn StreamerConnection) error { if !conn.CurrentlyStreaming() { return errors.New("exhaust read must be done with a connection that is currently streaming") } - scratch = scratch[:0] - res, err := op.readWireMessage(ctx, conn, scratch) + wm := memoryPool.Get().(*[]byte) + defer func() { + memoryPool.Put(wm) + }() + var res []byte + var err error + res, *wm, err = op.readWireMessage(ctx, conn, (*wm)[:0]) if err != nil { return err } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_legacy.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_legacy.go deleted file mode 100644 index 2584f484a..000000000 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/operation_legacy.go +++ /dev/null @@ -1,719 +0,0 @@ -// Copyright (C) MongoDB, Inc. 2017-present. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -package driver - -import ( - "context" - "errors" - "strconv" - "time" - - "go.mongodb.org/mongo-driver/bson/bsontype" - "go.mongodb.org/mongo-driver/mongo/description" - "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" - "go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage" -) - -var ( - firstBatchIdentifier = "firstBatch" - nextBatchIdentifier = "nextBatch" - listCollectionsNamespace = "system.namespaces" - listIndexesNamespace = "system.indexes" - - // ErrFilterType is returned when the filter for a legacy list collections operation is of the wrong type. - ErrFilterType = errors.New("filter for list collections operation must be a string") -) - -func (op Operation) getFullCollectionName(coll string) string { - return op.Database + "." + coll -} - -func (op Operation) legacyFind(ctx context.Context, dst []byte, srvr Server, conn Connection, desc description.SelectedServer) error { - wm, startedInfo, collName, err := op.createLegacyFindWireMessage(dst, desc) - if err != nil { - return err - } - startedInfo.connID = conn.ID() - op.publishStartedEvent(ctx, startedInfo) - - finishedInfo := finishedInformation{ - cmdName: startedInfo.cmdName, - requestID: startedInfo.requestID, - startTime: time.Now(), - connID: startedInfo.connID, - } - - finishedInfo.response, finishedInfo.cmdErr = op.roundTripLegacyCursor(ctx, wm, srvr, conn, collName, firstBatchIdentifier) - op.publishFinishedEvent(ctx, finishedInfo) - - if finishedInfo.cmdErr != nil { - return finishedInfo.cmdErr - } - - if op.ProcessResponseFn != nil { - // CurrentIndex is always 0 in this mode. - info := ResponseInfo{ - ServerResponse: finishedInfo.response, - Server: srvr, - Connection: conn, - ConnectionDescription: desc.Server, - } - return op.ProcessResponseFn(info) - } - return nil -} - -// returns wire message, collection name, error -func (op Operation) createLegacyFindWireMessage(dst []byte, desc description.SelectedServer) ([]byte, startedInformation, string, error) { - info := startedInformation{ - requestID: wiremessage.NextRequestID(), - cmdName: "find", - } - - // call CommandFn on an empty slice rather than dst because the options will need to be converted to legacy - var cmdDoc bsoncore.Document - var cmdIndex int32 - var err error - - cmdIndex, cmdDoc = bsoncore.AppendDocumentStart(cmdDoc) - cmdDoc, err = op.CommandFn(cmdDoc, desc) - if err != nil { - return dst, info, "", err - } - cmdDoc, _ = bsoncore.AppendDocumentEnd(cmdDoc, cmdIndex) - // for monitoring legacy events, the upconverted document should be captured rather than the legacy one - info.cmd = cmdDoc - - cmdElems, err := cmdDoc.Elements() - if err != nil { - return dst, info, "", err - } - - // take each option from the non-legacy command and convert it - // build options as a byte slice of elements rather than a bsoncore.Document because they will be appended - // to another document with $query - var optsElems []byte - flags := op.secondaryOK(desc) - var numToSkip, numToReturn, batchSize, limit int32 // numToReturn calculated from batchSize and limit - var filter, returnFieldsSelector bsoncore.Document - var collName string - var singleBatch bool - for _, elem := range cmdElems { - switch elem.Key() { - case "find": - collName = elem.Value().StringValue() - case "filter": - filter = elem.Value().Data - case "sort": - optsElems = bsoncore.AppendValueElement(optsElems, "$orderby", elem.Value()) - case "hint": - optsElems = bsoncore.AppendValueElement(optsElems, "$hint", elem.Value()) - case "comment": - optsElems = bsoncore.AppendValueElement(optsElems, "$comment", elem.Value()) - case "max": - optsElems = bsoncore.AppendValueElement(optsElems, "$max", elem.Value()) - case "min": - optsElems = bsoncore.AppendValueElement(optsElems, "$min", elem.Value()) - case "returnKey": - optsElems = bsoncore.AppendValueElement(optsElems, "$returnKey", elem.Value()) - case "showRecordId": - optsElems = bsoncore.AppendValueElement(optsElems, "$showDiskLoc", elem.Value()) - case "maxTimeMS": - optsElems = bsoncore.AppendValueElement(optsElems, "$maxTimeMS", elem.Value()) - case "snapshot": - optsElems = bsoncore.AppendValueElement(optsElems, "$snapshot", elem.Value()) - case "projection": - returnFieldsSelector = elem.Value().Data - case "skip": - // CRUD spec declares skip as int64 but numToSkip is int32 in OP_QUERY - numToSkip = int32(elem.Value().Int64()) - case "batchSize": - batchSize = elem.Value().Int32() - // Not possible to use batchSize = 1 because cursor will be closed on first batch - if batchSize == 1 { - batchSize = 2 - } - case "limit": - // CRUD spec declares limit as int64 but numToReturn is int32 in OP_QUERY - limit = int32(elem.Value().Int64()) - case "singleBatch": - singleBatch = elem.Value().Boolean() - case "tailable": - flags |= wiremessage.TailableCursor - case "awaitData": - flags |= wiremessage.AwaitData - case "oplogReplay": - flags |= wiremessage.OplogReplay - case "noCursorTimeout": - flags |= wiremessage.NoCursorTimeout - case "allowPartialResults": - flags |= wiremessage.Partial - } - } - - // for non-legacy servers, a negative limit is implemented as a positive limit + singleBatch = true - if singleBatch { - limit = limit * -1 - } - numToReturn = op.calculateNumberToReturn(limit, batchSize) - - // add read preference if needed - rp, err := op.createReadPref(desc, true) - if err != nil { - return dst, info, "", err - } - if len(rp) > 0 { - optsElems = bsoncore.AppendDocumentElement(optsElems, "$readPreference", rp) - } - - if len(filter) == 0 { - var fidx int32 - fidx, filter = bsoncore.AppendDocumentStart(filter) - filter, _ = bsoncore.AppendDocumentEnd(filter, fidx) - } - - var wmIdx int32 - wmIdx, dst = wiremessage.AppendHeaderStart(dst, info.requestID, 0, wiremessage.OpQuery) - dst = wiremessage.AppendQueryFlags(dst, flags) - dst = wiremessage.AppendQueryFullCollectionName(dst, op.getFullCollectionName(collName)) - dst = wiremessage.AppendQueryNumberToSkip(dst, numToSkip) - dst = wiremessage.AppendQueryNumberToReturn(dst, numToReturn) - dst = op.appendLegacyQueryDocument(dst, filter, optsElems) - if len(returnFieldsSelector) != 0 { - // returnFieldsSelector is optional - dst = append(dst, returnFieldsSelector...) - } - - return bsoncore.UpdateLength(dst, wmIdx, int32(len(dst[wmIdx:]))), info, collName, nil -} - -func (op Operation) calculateNumberToReturn(limit, batchSize int32) int32 { - var numToReturn int32 - - if limit < 0 { - numToReturn = limit - } else if limit == 0 { - numToReturn = batchSize - } else if batchSize == 0 { - numToReturn = limit - } else if limit < batchSize { - numToReturn = limit - } else { - numToReturn = batchSize - } - - return numToReturn -} - -func (op Operation) legacyGetMore(ctx context.Context, dst []byte, srvr Server, conn Connection, desc description.SelectedServer) error { - wm, startedInfo, collName, err := op.createLegacyGetMoreWiremessage(dst, desc) - if err != nil { - return err - } - - startedInfo.connID = conn.ID() - op.publishStartedEvent(ctx, startedInfo) - - finishedInfo := finishedInformation{ - cmdName: startedInfo.cmdName, - requestID: startedInfo.requestID, - startTime: time.Now(), - connID: startedInfo.connID, - } - finishedInfo.response, finishedInfo.cmdErr = op.roundTripLegacyCursor(ctx, wm, srvr, conn, collName, nextBatchIdentifier) - op.publishFinishedEvent(ctx, finishedInfo) - - if finishedInfo.cmdErr != nil { - return finishedInfo.cmdErr - } - - if op.ProcessResponseFn != nil { - // CurrentIndex is always 0 in this mode. - info := ResponseInfo{ - ServerResponse: finishedInfo.response, - Server: srvr, - Connection: conn, - ConnectionDescription: desc.Server, - } - return op.ProcessResponseFn(info) - } - return nil -} - -func (op Operation) createLegacyGetMoreWiremessage(dst []byte, desc description.SelectedServer) ([]byte, startedInformation, string, error) { - info := startedInformation{ - requestID: wiremessage.NextRequestID(), - cmdName: "getMore", - } - - var cmdDoc bsoncore.Document - var cmdIdx int32 - var err error - - cmdIdx, cmdDoc = bsoncore.AppendDocumentStart(cmdDoc) - cmdDoc, err = op.CommandFn(cmdDoc, desc) - if err != nil { - return dst, info, "", err - } - cmdDoc, _ = bsoncore.AppendDocumentEnd(cmdDoc, cmdIdx) - info.cmd = cmdDoc - - cmdElems, err := cmdDoc.Elements() - if err != nil { - return dst, info, "", err - } - - var cursorID int64 - var numToReturn int32 - var collName string - for _, elem := range cmdElems { - switch elem.Key() { - case "getMore": - cursorID = elem.Value().Int64() - case "collection": - collName = elem.Value().StringValue() - case "batchSize": - numToReturn = elem.Value().Int32() - } - } - - var wmIdx int32 - wmIdx, dst = wiremessage.AppendHeaderStart(dst, info.requestID, 0, wiremessage.OpGetMore) - dst = wiremessage.AppendGetMoreZero(dst) - dst = wiremessage.AppendGetMoreFullCollectionName(dst, op.getFullCollectionName(collName)) - dst = wiremessage.AppendGetMoreNumberToReturn(dst, numToReturn) - dst = wiremessage.AppendGetMoreCursorID(dst, cursorID) - - return bsoncore.UpdateLength(dst, wmIdx, int32(len(dst[wmIdx:]))), info, collName, nil -} - -func (op Operation) legacyKillCursors(ctx context.Context, dst []byte, srvr Server, conn Connection, desc description.SelectedServer) error { - wm, startedInfo, _, err := op.createLegacyKillCursorsWiremessage(dst, desc) - if err != nil { - return err - } - - startedInfo.connID = conn.ID() - op.publishStartedEvent(ctx, startedInfo) - - // skip startTime because OP_KILL_CURSORS does not return a response - finishedInfo := finishedInformation{ - cmdName: "killCursors", - requestID: startedInfo.requestID, - connID: startedInfo.connID, - } - - err = conn.WriteWireMessage(ctx, wm) - if err != nil { - err = Error{Message: err.Error(), Labels: []string{TransientTransactionError, NetworkError}} - if ep, ok := srvr.(ErrorProcessor); ok { - _ = ep.ProcessError(err, conn) - } - - finishedInfo.cmdErr = err - op.publishFinishedEvent(ctx, finishedInfo) - return err - } - - ridx, response := bsoncore.AppendDocumentStart(nil) - response = bsoncore.AppendInt32Element(response, "ok", 1) - response = bsoncore.AppendArrayElement(response, "cursorsUnknown", startedInfo.cmd.Lookup("cursors").Array()) - response, _ = bsoncore.AppendDocumentEnd(response, ridx) - - finishedInfo.response = response - op.publishFinishedEvent(ctx, finishedInfo) - return nil -} - -func (op Operation) createLegacyKillCursorsWiremessage(dst []byte, desc description.SelectedServer) ([]byte, startedInformation, string, error) { - info := startedInformation{ - cmdName: "killCursors", - requestID: wiremessage.NextRequestID(), - } - - var cmdDoc bsoncore.Document - var cmdIdx int32 - var err error - - cmdIdx, cmdDoc = bsoncore.AppendDocumentStart(cmdDoc) - cmdDoc, err = op.CommandFn(cmdDoc, desc) - if err != nil { - return nil, info, "", err - } - cmdDoc, _ = bsoncore.AppendDocumentEnd(cmdDoc, cmdIdx) - info.cmd = cmdDoc - - cmdElems, err := cmdDoc.Elements() - if err != nil { - return nil, info, "", err - } - - var collName string - var cursors bsoncore.Array - for _, elem := range cmdElems { - switch elem.Key() { - case "killCursors": - collName = elem.Value().StringValue() - case "cursors": - cursors = elem.Value().Array() - } - } - - var cursorIDs []int64 - if cursors != nil { - cursorValues, err := cursors.Values() - if err != nil { - return nil, info, "", err - } - - for _, cursorVal := range cursorValues { - cursorIDs = append(cursorIDs, cursorVal.Int64()) - } - } - - var wmIdx int32 - wmIdx, dst = wiremessage.AppendHeaderStart(dst, info.requestID, 0, wiremessage.OpKillCursors) - dst = wiremessage.AppendKillCursorsZero(dst) - dst = wiremessage.AppendKillCursorsNumberIDs(dst, int32(len(cursorIDs))) - dst = wiremessage.AppendKillCursorsCursorIDs(dst, cursorIDs) - - return bsoncore.UpdateLength(dst, wmIdx, int32(len(dst[wmIdx:]))), info, collName, nil -} - -func (op Operation) legacyListCollections(ctx context.Context, dst []byte, srvr Server, conn Connection, desc description.SelectedServer) error { - wm, startedInfo, collName, err := op.createLegacyListCollectionsWiremessage(dst, desc) - if err != nil { - return err - } - startedInfo.connID = conn.ID() - op.publishStartedEvent(ctx, startedInfo) - - finishedInfo := finishedInformation{ - cmdName: startedInfo.cmdName, - requestID: startedInfo.requestID, - startTime: time.Now(), - connID: startedInfo.connID, - } - - finishedInfo.response, finishedInfo.cmdErr = op.roundTripLegacyCursor(ctx, wm, srvr, conn, collName, firstBatchIdentifier) - op.publishFinishedEvent(ctx, finishedInfo) - - if finishedInfo.cmdErr != nil { - return finishedInfo.cmdErr - } - - if op.ProcessResponseFn != nil { - // CurrentIndex is always 0 in this mode. - info := ResponseInfo{ - ServerResponse: finishedInfo.response, - Server: srvr, - Connection: conn, - ConnectionDescription: desc.Server, - } - return op.ProcessResponseFn(info) - } - return nil -} - -func (op Operation) createLegacyListCollectionsWiremessage(dst []byte, desc description.SelectedServer) ([]byte, startedInformation, string, error) { - info := startedInformation{ - cmdName: "find", - requestID: wiremessage.NextRequestID(), - } - - var cmdDoc bsoncore.Document - var cmdIdx int32 - var err error - - cmdIdx, cmdDoc = bsoncore.AppendDocumentStart(cmdDoc) - if cmdDoc, err = op.CommandFn(cmdDoc, desc); err != nil { - return dst, info, "", err - } - cmdDoc, _ = bsoncore.AppendDocumentEnd(cmdDoc, cmdIdx) - info.cmd, err = op.convertCommandToFind(cmdDoc, listCollectionsNamespace) - if err != nil { - return nil, info, "", err - } - - // lookup filter directly instead of calling cmdDoc.Elements() because the only listCollections option is nameOnly, - // which doesn't apply to legacy servers - var originalFilter bsoncore.Document - if filterVal, err := cmdDoc.LookupErr("filter"); err == nil { - originalFilter = filterVal.Document() - } - - var optsElems []byte - filter, err := op.transformListCollectionsFilter(originalFilter) - if err != nil { - return dst, info, "", err - } - rp, err := op.createReadPref(desc, true) - if err != nil { - return dst, info, "", err - } - if len(rp) > 0 { - optsElems = bsoncore.AppendDocumentElement(optsElems, "$readPreference", rp) - } - - var batchSize int32 - if val, ok := cmdDoc.Lookup("cursor", "batchSize").AsInt32OK(); ok { - batchSize = val - } - - var wmIdx int32 - wmIdx, dst = wiremessage.AppendHeaderStart(dst, info.requestID, 0, wiremessage.OpQuery) - dst = wiremessage.AppendQueryFlags(dst, op.secondaryOK(desc)) - dst = wiremessage.AppendQueryFullCollectionName(dst, op.getFullCollectionName(listCollectionsNamespace)) - dst = wiremessage.AppendQueryNumberToSkip(dst, 0) - dst = wiremessage.AppendQueryNumberToReturn(dst, batchSize) - dst = op.appendLegacyQueryDocument(dst, filter, optsElems) - // leave out returnFieldsSelector because it is optional - - return bsoncore.UpdateLength(dst, wmIdx, int32(len(dst[wmIdx:]))), info, listCollectionsNamespace, nil -} - -func (op Operation) transformListCollectionsFilter(filter bsoncore.Document) (bsoncore.Document, error) { - // filter out results containing $ because those represent indexes - var regexFilter bsoncore.Document - var ridx int32 - ridx, regexFilter = bsoncore.AppendDocumentStart(regexFilter) - regexFilter = bsoncore.AppendRegexElement(regexFilter, "name", "^[^$]*$", "") - regexFilter, _ = bsoncore.AppendDocumentEnd(regexFilter, ridx) - - if len(filter) == 0 { - return regexFilter, nil - } - - convertedIdx, convertedFilter := bsoncore.AppendDocumentStart(nil) - elems, err := filter.Elements() - if err != nil { - return nil, err - } - - for _, elem := range elems { - if elem.Key() != "name" { - convertedFilter = append(convertedFilter, elem...) - continue - } - - // the name value in a filter for legacy list collections must be a string and has to be prepended - // with the database name - nameVal := elem.Value() - if nameVal.Type != bsontype.String { - return nil, ErrFilterType - } - convertedFilter = bsoncore.AppendStringElement(convertedFilter, "name", op.getFullCollectionName(nameVal.StringValue())) - } - convertedFilter, _ = bsoncore.AppendDocumentEnd(convertedFilter, convertedIdx) - - // combine regexFilter and convertedFilter with $and - var combinedFilter bsoncore.Document - var cidx, aidx int32 - cidx, combinedFilter = bsoncore.AppendDocumentStart(combinedFilter) - aidx, combinedFilter = bsoncore.AppendArrayElementStart(combinedFilter, "$and") - combinedFilter = bsoncore.AppendDocumentElement(combinedFilter, "0", regexFilter) - combinedFilter = bsoncore.AppendDocumentElement(combinedFilter, "1", convertedFilter) - combinedFilter, _ = bsoncore.AppendArrayEnd(combinedFilter, aidx) - combinedFilter, _ = bsoncore.AppendDocumentEnd(combinedFilter, cidx) - - return combinedFilter, nil -} - -func (op Operation) legacyListIndexes(ctx context.Context, dst []byte, srvr Server, conn Connection, desc description.SelectedServer) error { - wm, startedInfo, collName, err := op.createLegacyListIndexesWiremessage(dst, desc) - if err != nil { - return err - } - startedInfo.connID = conn.ID() - op.publishStartedEvent(ctx, startedInfo) - - finishedInfo := finishedInformation{ - cmdName: startedInfo.cmdName, - requestID: startedInfo.requestID, - startTime: time.Now(), - connID: startedInfo.connID, - } - - finishedInfo.response, finishedInfo.cmdErr = op.roundTripLegacyCursor(ctx, wm, srvr, conn, collName, firstBatchIdentifier) - op.publishFinishedEvent(ctx, finishedInfo) - - if finishedInfo.cmdErr != nil { - return finishedInfo.cmdErr - } - - if op.ProcessResponseFn != nil { - // CurrentIndex is always 0 in this mode. - info := ResponseInfo{ - ServerResponse: finishedInfo.response, - Server: srvr, - Connection: conn, - ConnectionDescription: desc.Server, - } - return op.ProcessResponseFn(info) - } - return nil -} - -func (op Operation) createLegacyListIndexesWiremessage(dst []byte, desc description.SelectedServer) ([]byte, startedInformation, string, error) { - info := startedInformation{ - cmdName: "find", - requestID: wiremessage.NextRequestID(), - } - - var cmdDoc bsoncore.Document - var cmdIndex int32 - var err error - - cmdIndex, cmdDoc = bsoncore.AppendDocumentStart(cmdDoc) - cmdDoc, err = op.CommandFn(cmdDoc, desc) - if err != nil { - return dst, info, "", err - } - cmdDoc, _ = bsoncore.AppendDocumentEnd(cmdDoc, cmdIndex) - info.cmd, err = op.convertCommandToFind(cmdDoc, listIndexesNamespace) - if err != nil { - return nil, info, "", err - } - - cmdElems, err := cmdDoc.Elements() - if err != nil { - return nil, info, "", err - } - - var filterCollName string - var batchSize int32 - var optsElems []byte // options elements - for _, elem := range cmdElems { - switch elem.Key() { - case "listIndexes": - filterCollName = elem.Value().StringValue() - case "cursor": - // the batchSize option is embedded in a cursor subdocument - cursorDoc := elem.Value().Document() - if val, err := cursorDoc.LookupErr("batchSize"); err == nil { - batchSize = val.Int32() - } - case "maxTimeMS": - optsElems = bsoncore.AppendValueElement(optsElems, "$maxTimeMS", elem.Value()) - } - } - - // always filter with {ns: db.collection} - fidx, filter := bsoncore.AppendDocumentStart(nil) - filter = bsoncore.AppendStringElement(filter, "ns", op.getFullCollectionName(filterCollName)) - filter, _ = bsoncore.AppendDocumentEnd(filter, fidx) - - rp, err := op.createReadPref(desc, true) - if err != nil { - return dst, info, "", err - } - if len(rp) > 0 { - optsElems = bsoncore.AppendDocumentElement(optsElems, "$readPreference", rp) - } - - var wmIdx int32 - wmIdx, dst = wiremessage.AppendHeaderStart(dst, info.requestID, 0, wiremessage.OpQuery) - dst = wiremessage.AppendQueryFlags(dst, op.secondaryOK(desc)) - dst = wiremessage.AppendQueryFullCollectionName(dst, op.getFullCollectionName(listIndexesNamespace)) - dst = wiremessage.AppendQueryNumberToSkip(dst, 0) - dst = wiremessage.AppendQueryNumberToReturn(dst, batchSize) - dst = op.appendLegacyQueryDocument(dst, filter, optsElems) - // leave out returnFieldsSelector because it is optional - - return bsoncore.UpdateLength(dst, wmIdx, int32(len(dst[wmIdx:]))), info, listIndexesNamespace, nil -} - -// convertCommandToFind takes a non-legacy command document for a command that needs to be run as a find on legacy -// servers and converts it to a find command document for APM. -func (op Operation) convertCommandToFind(cmdDoc bsoncore.Document, collName string) (bsoncore.Document, error) { - cidx, converted := bsoncore.AppendDocumentStart(nil) - elems, err := cmdDoc.Elements() - if err != nil { - return nil, err - } - - converted = bsoncore.AppendStringElement(converted, "find", collName) - // skip the first element because that will have the old command name - for i := 1; i < len(elems); i++ { - converted = bsoncore.AppendValueElement(converted, elems[i].Key(), elems[i].Value()) - } - - converted, _ = bsoncore.AppendDocumentEnd(converted, cidx) - return converted, nil -} - -// appendLegacyQueryDocument takes a filter and a list of options elements for a legacy find operation, creates -// a query document, and appends it to dst. -func (op Operation) appendLegacyQueryDocument(dst []byte, filter bsoncore.Document, opts []byte) []byte { - if len(opts) == 0 { - dst = append(dst, filter...) - return dst - } - - // filter must be wrapped in $query if other $-modifiers are used - var qidx int32 - qidx, dst = bsoncore.AppendDocumentStart(dst) - dst = bsoncore.AppendDocumentElement(dst, "$query", filter) - dst = append(dst, opts...) - dst, _ = bsoncore.AppendDocumentEnd(dst, qidx) - return dst -} - -// roundTripLegacyCursor sends a wiremessage for an operation expecting a cursor result and converts the legacy -// document sequence into a cursor document. -func (op Operation) roundTripLegacyCursor(ctx context.Context, wm []byte, srvr Server, conn Connection, collName, identifier string) (bsoncore.Document, error) { - wm, err := op.roundTripLegacy(ctx, conn, wm) - if ep, ok := srvr.(ErrorProcessor); ok { - _ = ep.ProcessError(err, conn) - } - if err != nil { - return nil, err - } - - return op.upconvertCursorResponse(wm, identifier, collName) -} - -// roundTripLegacy handles writing a wire message and reading the response. -func (op Operation) roundTripLegacy(ctx context.Context, conn Connection, wm []byte) ([]byte, error) { - err := conn.WriteWireMessage(ctx, wm) - if err != nil { - return nil, Error{Message: err.Error(), Labels: []string{TransientTransactionError, NetworkError}, Wrapped: err} - } - - wm, err = conn.ReadWireMessage(ctx, wm[:0]) - if err != nil { - err = Error{Message: err.Error(), Labels: []string{TransientTransactionError, NetworkError}, Wrapped: err} - } - return wm, err -} - -func (op Operation) upconvertCursorResponse(wm []byte, batchIdentifier string, collName string) (bsoncore.Document, error) { - reply := op.decodeOpReply(wm, true) - if reply.err != nil { - return nil, reply.err - } - - cursorIdx, cursorDoc := bsoncore.AppendDocumentStart(nil) - // convert reply documents to BSON array - var arrIdx int32 - arrIdx, cursorDoc = bsoncore.AppendArrayElementStart(cursorDoc, batchIdentifier) - for i, doc := range reply.documents { - cursorDoc = bsoncore.AppendDocumentElement(cursorDoc, strconv.Itoa(i), doc) - } - cursorDoc, _ = bsoncore.AppendArrayEnd(cursorDoc, arrIdx) - - cursorDoc = bsoncore.AppendInt64Element(cursorDoc, "id", reply.cursorID) - cursorDoc = bsoncore.AppendStringElement(cursorDoc, "ns", op.getFullCollectionName(collName)) - cursorDoc, _ = bsoncore.AppendDocumentEnd(cursorDoc, cursorIdx) - - resIdx, resDoc := bsoncore.AppendDocumentStart(nil) - resDoc = bsoncore.AppendInt32Element(resDoc, "ok", 1) - resDoc = bsoncore.AppendDocumentElement(resDoc, "cursor", cursorDoc) - resDoc, _ = bsoncore.AppendDocumentEnd(resDoc, resIdx) - - return resDoc, nil -} diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/client_session.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/client_session.go index da85ac017..dfa09b84e 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/client_session.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/client_session.go @@ -215,16 +215,24 @@ func NewClientSession(pool *Pool, clientID uuid.UUID, sessionType Type, opts ... return nil, errors.New("causal consistency and snapshot cannot both be set for a session") } - servSess, err := pool.GetSession() - if err != nil { - return nil, err + // Server checkout for implicit sessions are deferred until after checking out a connection. This will limit the + // number of implicit sessions to no greater than an applications maxPoolSize. + if sessionType == Explicit { + if err := c.SetServer(); err != nil { + return nil, err + } } - c.Server = servSess - return c, nil } +// SetServer will check out a session from the client session pool. +func (c *Client) SetServer() error { + var err error + c.Server, err = c.pool.GetSession() + return err +} + // AdvanceClusterTime updates the session's cluster time. func (c *Client) AdvanceClusterTime(clusterTime bson.Raw) error { if c.Terminated { @@ -343,7 +351,6 @@ func (c *Client) EndSession() { if c.Terminated { return } - c.Terminated = true c.pool.ReturnSession(c.Server) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/session_pool.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/session_pool.go index 27db7c476..34b863c11 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/session_pool.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/session/session_pool.go @@ -8,6 +8,7 @@ package session import ( "sync" + "sync/atomic" "go.mongodb.org/mongo-driver/mongo/description" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" @@ -29,13 +30,14 @@ type topologyDescription struct { // Pool is a pool of server sessions that can be reused. type Pool struct { + // number of sessions checked out of pool (accessed atomically) + checkedOut int64 + descChan <-chan description.Topology head *Node tail *Node latestTopology topologyDescription mutex sync.Mutex // mutex to protect list and sessionTimeout - - checkedOut int // number of sessions checked out of pool } func (p *Pool) createServerSession() (*Server, error) { @@ -44,7 +46,7 @@ func (p *Pool) createServerSession() (*Server, error) { return nil, err } - p.checkedOut++ + atomic.AddInt64(&p.checkedOut, 1) return s, nil } @@ -100,7 +102,7 @@ func (p *Pool) GetSession() (*Server, error) { p.head = p.head.next } - p.checkedOut++ + atomic.AddInt64(&p.checkedOut, 1) return session, nil } @@ -118,7 +120,7 @@ func (p *Pool) ReturnSession(ss *Server) { p.mutex.Lock() defer p.mutex.Unlock() - p.checkedOut-- + atomic.AddInt64(&p.checkedOut, -1) p.updateTimeout() // check sessions at end of queue for expired // stop checking after hitting the first valid session @@ -185,6 +187,6 @@ func (p *Pool) String() string { } // CheckedOut returns number of sessions checked out from pool. -func (p *Pool) CheckedOut() int { - return p.checkedOut +func (p *Pool) CheckedOut() int64 { + return atomic.LoadInt64(&p.checkedOut) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection.go index 34cb6c957..e54a6d482 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection.go @@ -200,6 +200,7 @@ func (c *connection) connect(ctx context.Context) (err error) { ocspOpts := &ocsp.VerifyOptions{ Cache: c.config.ocspCache, DisableEndpointChecking: c.config.disableOCSPEndpointCheck, + HTTPClient: c.config.httpClient, } tlsNc, err := configureTLS(dialCtx, c.config.tlsConnectionSource, c.nc, c.addr, tlsConfig, ocspOpts) if err != nil { @@ -406,7 +407,7 @@ func (c *connection) readWireMessage(ctx context.Context, dst []byte) ([]byte, e if err == io.EOF { message = "socket was unexpectedly closed" } - return nil, ConnectionError{ + return dst, ConnectionError{ ConnectionID: c.id, Wrapped: transformNetworkError(ctx, err, contextDeadlineUsed), message: message, @@ -438,7 +439,7 @@ func (c *connection) read(ctx context.Context, dst []byte) (bytesRead []byte, er // reading messages from an exhaust cursor. _, err = io.ReadFull(c.nc, sizeBuf[:]) if err != nil { - return nil, "incomplete read of message header", err + return dst, "incomplete read of message header", err } // read the length as an int32 @@ -451,7 +452,7 @@ func (c *connection) read(ctx context.Context, dst []byte) (bytesRead []byte, er maxMessageSize = defaultMaxMessageSize } if uint32(size) > maxMessageSize { - return nil, errResponseTooLarge.Error(), errResponseTooLarge + return dst, errResponseTooLarge.Error(), errResponseTooLarge } if int(size) > cap(dst) { @@ -465,7 +466,7 @@ func (c *connection) read(ctx context.Context, dst []byte) (bytesRead []byte, er _, err = io.ReadFull(c.nc, dst[4:]) if err != nil { - return nil, "incomplete read of full message", err + return dst, "incomplete read of full message", err } return dst, "", nil @@ -625,9 +626,6 @@ func (c *Connection) CompressWireMessage(src, dst []byte) ([]byte, error) { return dst, ErrConnectionClosed } if c.connection.compressor == wiremessage.CompressorNoOp { - if len(dst) == 0 { - return src, nil - } return append(dst, src...), nil } _, reqid, respto, origcode, rem, ok := wiremessage.ReadHeader(src) diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection_options.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection_options.go index 1d4793e4a..6e6ea01d8 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection_options.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/connection_options.go @@ -10,10 +10,12 @@ import ( "context" "crypto/tls" "net" + "net/http" "time" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/event" + "go.mongodb.org/mongo-driver/internal" "go.mongodb.org/mongo-driver/x/mongo/driver" "go.mongodb.org/mongo-driver/x/mongo/driver/ocsp" ) @@ -54,6 +56,7 @@ type connectionConfig struct { readTimeout time.Duration writeTimeout time.Duration tlsConfig *tls.Config + httpClient *http.Client compressors []string zlibLevel *int zstdLevel *int @@ -69,6 +72,7 @@ func newConnectionConfig(opts ...ConnectionOption) *connectionConfig { connectTimeout: 30 * time.Second, dialer: nil, tlsConnectionSource: defaultTLSConnectionSource, + httpClient: internal.DefaultHTTPClient, } for _, opt := range opts { @@ -152,6 +156,13 @@ func WithTLSConfig(fn func(*tls.Config) *tls.Config) ConnectionOption { } } +// WithHTTPClient configures the HTTP client for a connection. +func WithHTTPClient(fn func(*http.Client) *http.Client) ConnectionOption { + return func(c *connectionConfig) { + c.httpClient = fn(c.httpClient) + } +} + // WithMonitor configures a event for command monitoring. func WithMonitor(fn func(*event.CommandMonitor) *event.CommandMonitor) ConnectionOption { return func(c *connectionConfig) { diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/errors.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/errors.go index 4aa99857e..4f7b48540 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/errors.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/errors.go @@ -7,6 +7,7 @@ package topology import ( + "context" "fmt" "go.mongodb.org/mongo-driver/mongo/description" @@ -78,8 +79,20 @@ type WaitQueueTimeoutError struct { // Error implements the error interface. func (w WaitQueueTimeoutError) Error() string { errorMsg := "timed out while checking out a connection from connection pool" - if w.Wrapped != nil { - errorMsg = fmt.Sprintf("%s: %s", errorMsg, w.Wrapped.Error()) + switch w.Wrapped { + case nil: + case context.Canceled: + errorMsg = fmt.Sprintf( + "%s: %s", + "canceled while checking out a connection from connection pool", + w.Wrapped.Error(), + ) + default: + errorMsg = fmt.Sprintf( + "%s: %s", + errorMsg, + w.Wrapped.Error(), + ) } return fmt.Sprintf( diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/fsm.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/fsm.go index b1bf0c4a7..1ee8dce49 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/fsm.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/fsm.go @@ -17,13 +17,11 @@ import ( ) var ( - // SupportedWireVersions is the range of wire versions supported by the driver. - SupportedWireVersions = description.NewVersionRange(2, 17) -) - -const ( // MinSupportedMongoDBVersion is the version string for the lowest MongoDB version supported by the driver. - MinSupportedMongoDBVersion = "2.6" + MinSupportedMongoDBVersion = "3.6" + + // SupportedWireVersions is the range of wire versions supported by the driver. + SupportedWireVersions = description.NewVersionRange(6, 17) ) type fsm struct { @@ -230,30 +228,78 @@ func (f *fsm) checkIfHasPrimary() { } } -func (f *fsm) updateRSFromPrimary(s description.Server) { - if f.SetName == "" { - f.SetName = s.SetName - } else if f.SetName != s.SetName { - f.removeServerByAddr(s.Addr) - f.checkIfHasPrimary() - return +// hasStalePrimary returns true if the topology has a primary that is "stale". +func hasStalePrimary(fsm fsm, srv description.Server) bool { + // Compare the election ID values of the server and the topology lexicographically. + compRes := bytes.Compare(srv.ElectionID[:], fsm.maxElectionID[:]) + + if wireVersion := srv.WireVersion; wireVersion != nil && wireVersion.Max >= 17 { + // In the Post-6.0 case, a primary is considered "stale" if the server's election ID is greather than the + // topology's max election ID. In these versions, the primary is also considered "stale" if the server's + // election ID is LTE to the topologies election ID and the server's "setVersion" is less than the topology's + // max "setVersion". + return compRes == -1 || (compRes != 1 && srv.SetVersion < fsm.maxSetVersion) } - if s.SetVersion != 0 && !s.ElectionID.IsZero() { - if f.maxSetVersion > s.SetVersion || bytes.Compare(f.maxElectionID[:], s.ElectionID[:]) == 1 { - f.replaceServer(description.Server{ - Addr: s.Addr, - LastError: fmt.Errorf("was a primary, but its set version or election id is stale"), + // If the server's election ID is less than the topology's max election ID, the primary is considered + // "stale". Similarly, if the server's "setVersion" is less than the topology's max "setVersion", the + // primary is considered stale. + return compRes == -1 || fsm.maxSetVersion > srv.SetVersion +} + +// transferEVTuple will transfer the ("ElectionID", "SetVersion") tuple from the description server to the topology. +// If the primary is stale, the tuple will not be transferred, the topology will update it's "Kind" value, and this +// routine will return "false". +func transferEVTuple(srv description.Server, fsm *fsm) bool { + stalePrimary := hasStalePrimary(*fsm, srv) + + if wireVersion := srv.WireVersion; wireVersion != nil && wireVersion.Max >= 17 { + if stalePrimary { + fsm.checkIfHasPrimary() + return false + } + + fsm.maxElectionID = srv.ElectionID + fsm.maxSetVersion = srv.SetVersion + + return true + } + + if srv.SetVersion != 0 && !srv.ElectionID.IsZero() { + if stalePrimary { + fsm.replaceServer(description.Server{ + Addr: srv.Addr, + LastError: fmt.Errorf( + "was a primary, but its set version or election id is stale"), }) - f.checkIfHasPrimary() - return + + fsm.checkIfHasPrimary() + + return false } - f.maxElectionID = s.ElectionID + fsm.maxElectionID = srv.ElectionID } - if s.SetVersion > f.maxSetVersion { - f.maxSetVersion = s.SetVersion + if srv.SetVersion > fsm.maxSetVersion { + fsm.maxSetVersion = srv.SetVersion + } + + return true +} + +func (f *fsm) updateRSFromPrimary(srv description.Server) { + if f.SetName == "" { + f.SetName = srv.SetName + } else if f.SetName != srv.SetName { + f.removeServerByAddr(srv.Addr) + f.checkIfHasPrimary() + + return + } + + if ok := transferEVTuple(srv, f); !ok { + return } if j, ok := f.findPrimary(); ok { @@ -263,22 +309,23 @@ func (f *fsm) updateRSFromPrimary(s description.Server) { }) } - f.replaceServer(s) + f.replaceServer(srv) for j := len(f.Servers) - 1; j >= 0; j-- { found := false - for _, member := range s.Members { + for _, member := range srv.Members { if member == f.Servers[j].Addr { found = true break } } + if !found { f.removeServer(j) } } - for _, member := range s.Members { + for _, member := range srv.Members { if _, ok := f.findServer(member); !ok { f.addServer(member) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/rtt_monitor.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/rtt_monitor.go index 723f0fa84..998d2a025 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/rtt_monitor.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/rtt_monitor.go @@ -43,7 +43,7 @@ type rttMonitor struct { samples []time.Duration offset int minRTT time.Duration - RTT90 time.Duration + rtt90 time.Duration averageRTT time.Duration averageRTTSet bool @@ -53,6 +53,8 @@ type rttMonitor struct { cancelFn context.CancelFunc } +var _ driver.RTTMonitor = &rttMonitor{} + func newRTTMonitor(cfg *rttConfig) *rttMonitor { if cfg.interval <= 0 { panic("RTT monitor interval must be greater than 0") @@ -179,7 +181,7 @@ func (r *rttMonitor) reset() { } r.offset = 0 r.minRTT = 0 - r.RTT90 = 0 + r.rtt90 = 0 r.averageRTT = 0 r.averageRTTSet = false } @@ -196,7 +198,7 @@ func (r *rttMonitor) addSample(rtt time.Duration) { // setting these to prevent noisy samples on startup from artificially increasing RTT and to allow the // calculation of a 90th percentile. r.minRTT = min(r.samples, minSamples) - r.RTT90 = percentile(90.0, r.samples, minSamples) + r.rtt90 = percentile(90.0, r.samples, minSamples) if !r.averageRTTSet { r.averageRTT = rtt @@ -249,26 +251,57 @@ func percentile(perc float64, samples []time.Duration, minSamples int) time.Dura return time.Duration(p) } -// getRTT returns the exponentially weighted moving average observed round-trip time. -func (r *rttMonitor) getRTT() time.Duration { +// EWMA returns the exponentially weighted moving average observed round-trip time. +func (r *rttMonitor) EWMA() time.Duration { r.mu.RLock() defer r.mu.RUnlock() return r.averageRTT } -// getMinRTT returns the minimum observed round-trip time over the window period. -func (r *rttMonitor) getMinRTT() time.Duration { +// Min returns the minimum observed round-trip time over the window period. +func (r *rttMonitor) Min() time.Duration { r.mu.RLock() defer r.mu.RUnlock() return r.minRTT } -// getRTT90 returns the 90th percentile observed round-trip time over the window period. -func (r *rttMonitor) getRTT90() time.Duration { +// P90 returns the 90th percentile observed round-trip time over the window period. +func (r *rttMonitor) P90() time.Duration { + r.mu.RLock() + defer r.mu.RUnlock() + + return r.rtt90 +} + +// Stats returns stringified stats of the current state of the monitor. +func (r *rttMonitor) Stats() string { r.mu.RLock() defer r.mu.RUnlock() - return r.RTT90 + // Calculate standard deviation and average (non-EWMA) of samples. + var sum float64 + floatSamples := make([]float64, 0, len(r.samples)) + for _, sample := range r.samples { + if sample > 0 { + floatSamples = append(floatSamples, float64(sample)) + sum += float64(sample) + } + } + + var avg, stdDev float64 + if len(floatSamples) > 0 { + avg = sum / float64(len(floatSamples)) + + var err error + stdDev, err = stats.StandardDeviation(floatSamples) + if err != nil { + panic(fmt.Errorf("x/mongo/driver/topology: error calculating standard deviation RTT: %v for samples:\n%v", err, floatSamples)) + } + } + + return fmt.Sprintf(`Round-trip-time monitor statistics:`+"\n"+ + `average RTT: %v, minimum RTT: %v, 90th percentile RTT: %v, standard dev: %v`+"\n", + time.Duration(avg), r.minRTT, r.rtt90, time.Duration(stdDev)) } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server.go index 6915ef035..bdd9035ea 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server.go @@ -779,7 +779,7 @@ func (s *Server) check() (description.Server, error) { if descPtr != nil { // The check was successful. Set the average RTT and the 90th percentile RTT and return. desc := *descPtr - desc = desc.SetAverageRTT(s.rttMonitor.getRTT()) + desc = desc.SetAverageRTT(s.rttMonitor.EWMA()) desc.HeartbeatInterval = s.cfg.heartbeatInterval return desc, nil } @@ -814,14 +814,9 @@ func extractTopologyVersion(err error) *description.TopologyVersion { return nil } -// MinRTT returns the minimum round-trip time to the server observed over the last 5 minutes. -func (s *Server) MinRTT() time.Duration { - return s.rttMonitor.getMinRTT() -} - -// RTT90 returns the 90th percentile round-trip time to the server observed over the last 5 minutes. -func (s *Server) RTT90() time.Duration { - return s.rttMonitor.getRTT90() +// RTTMonitor returns this server's round-trip-time monitor. +func (s *Server) RTTMonitor() driver.RTTMonitor { + return s.rttMonitor } // OperationCount returns the current number of in-progress operations for this server. @@ -839,7 +834,7 @@ func (s *Server) String() string { str += fmt.Sprintf(", Tag sets: %s", desc.Tags) } if state == serverConnected { - str += fmt.Sprintf(", Average RTT: %s, Min RTT: %s", desc.AverageRTT, s.MinRTT()) + str += fmt.Sprintf(", Average RTT: %s, Min RTT: %s", desc.AverageRTT, s.RTTMonitor().Min()) } if desc.LastError != nil { str += fmt.Sprintf(", Last error: %s", desc.LastError) diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server_options.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server_options.go index 53215697b..73819f9fc 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server_options.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/server_options.go @@ -60,6 +60,12 @@ func newServerConfig(opts ...ServerOption) *serverConfig { // ServerOption configures a server. type ServerOption func(*serverConfig) +// ServerAPIFromServerOptions will return the server API options if they have been functionally set on the ServerOption +// slice. +func ServerAPIFromServerOptions(opts []ServerOption) *driver.ServerAPIOptions { + return newServerConfig(opts...).serverAPI +} + func withMonitoringDisabled(fn func(bool) bool) ServerOption { return func(cfg *serverConfig) { cfg.monitoringDisabled = fn(cfg.monitoringDisabled) diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology.go index f02e5dea8..eb0ac425a 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology.go @@ -14,6 +14,8 @@ import ( "context" "errors" "fmt" + "net" + "net/url" "strings" "sync" "sync/atomic" @@ -24,6 +26,7 @@ import ( "go.mongodb.org/mongo-driver/internal/randutil" "go.mongodb.org/mongo-driver/mongo/address" "go.mongodb.org/mongo-driver/mongo/description" + "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/x/mongo/driver" "go.mongodb.org/mongo-driver/x/mongo/driver/dns" ) @@ -68,7 +71,7 @@ const ( type Topology struct { state int64 - cfg *config + cfg *Config desc atomic.Value // holds a description.Topology @@ -119,11 +122,14 @@ func newServerSelectionState(selector description.ServerSelector, timeoutChan <- } } -// New creates a new topology. -func New(opts ...Option) (*Topology, error) { - cfg, err := newConfig(opts...) - if err != nil { - return nil, err +// New creates a new topology. A "nil" config is interpreted as the default configuration. +func New(cfg *Config) (*Topology, error) { + if cfg == nil { + var err error + cfg, err = NewConfig(options.Client(), nil) + if err != nil { + return nil, err + } } t := &Topology{ @@ -142,8 +148,8 @@ func New(opts ...Option) (*Topology, error) { return t.apply(context.TODO(), desc) } - if t.cfg.uri != "" { - t.pollingRequired = strings.HasPrefix(t.cfg.uri, "mongodb+srv://") && !t.cfg.loadBalanced + if t.cfg.URI != "" { + t.pollingRequired = strings.HasPrefix(t.cfg.URI, "mongodb+srv://") && !t.cfg.LoadBalanced } t.publishTopologyOpeningEvent() @@ -164,23 +170,23 @@ func (t *Topology) Connect() error { // A replica set name sets the initial topology type to ReplicaSetNoPrimary unless a direct connection is also // specified, in which case the initial type is Single. - if t.cfg.replicaSetName != "" { - t.fsm.SetName = t.cfg.replicaSetName + if t.cfg.ReplicaSetName != "" { + t.fsm.SetName = t.cfg.ReplicaSetName t.fsm.Kind = description.ReplicaSetNoPrimary } // A direct connection unconditionally sets the topology type to Single. - if t.cfg.mode == SingleMode { + if t.cfg.Mode == SingleMode { t.fsm.Kind = description.Single } - for _, a := range t.cfg.seedList { + for _, a := range t.cfg.SeedList { addr := address.Address(a).Canonicalize() t.fsm.Servers = append(t.fsm.Servers, description.NewDefaultServer(addr)) } switch { - case t.cfg.loadBalanced: + case t.cfg.LoadBalanced: // In LoadBalanced mode, we mock a series of events: TopologyDescriptionChanged from Unknown to LoadBalanced, // ServerDescriptionChanged from Unknown to LoadBalancer, and then TopologyDescriptionChanged to reflect the // previous ServerDescriptionChanged event. We publish all of these events here because we don't start server @@ -190,7 +196,7 @@ func (t *Topology) Connect() error { t.fsm.Kind = description.LoadBalanced t.publishTopologyDescriptionChangedEvent(description.Topology{}, t.fsm.Topology) - addr := address.Address(t.cfg.seedList[0]).Canonicalize() + addr := address.Address(t.cfg.SeedList[0]).Canonicalize() if err := t.addServer(addr); err != nil { t.serversLock.Unlock() return err @@ -218,7 +224,7 @@ func (t *Topology) Connect() error { } t.desc.Store(newDesc) t.publishTopologyDescriptionChangedEvent(description.Topology{}, t.fsm.Topology) - for _, a := range t.cfg.seedList { + for _, a := range t.cfg.SeedList { addr := address.Address(a).Canonicalize() err = t.addServer(addr) if err != nil { @@ -230,7 +236,21 @@ func (t *Topology) Connect() error { t.serversLock.Unlock() if t.pollingRequired { - go t.pollSRVRecords() + uri, err := url.Parse(t.cfg.URI) + if err != nil { + return err + } + // sanity check before passing the hostname to resolver + if parsedHosts := strings.Split(uri.Host, ","); len(parsedHosts) != 1 { + return fmt.Errorf("URI with SRV must include one and only one hostname") + } + _, _, err = net.SplitHostPort(uri.Host) + if err == nil { + // we were able to successfully extract a port from the host, + // but should not be able to when using SRV + return fmt.Errorf("URI with srv must not include a port number") + } + go t.pollSRVRecords(uri.Host) t.pollingwg.Add(1) } @@ -364,8 +384,8 @@ func (t *Topology) SelectServer(ctx context.Context, ss description.ServerSelect } var ssTimeoutCh <-chan time.Time - if t.cfg.serverSelectionTimeout > 0 { - ssTimeout := time.NewTimer(t.cfg.serverSelectionTimeout) + if t.cfg.ServerSelectionTimeout > 0 { + ssTimeout := time.NewTimer(t.cfg.ServerSelectionTimeout) ssTimeoutCh = ssTimeout.C defer ssTimeout.Stop() } @@ -552,10 +572,10 @@ func (t *Topology) selectServerFromDescription(desc description.Topology, return suitable, nil } -func (t *Topology) pollSRVRecords() { +func (t *Topology) pollSRVRecords(hosts string) { defer t.pollingwg.Done() - serverConfig := newServerConfig(t.cfg.serverOpts...) + serverConfig := newServerConfig(t.cfg.ServerOpts...) heartbeatInterval := serverConfig.heartbeatInterval pollTicker := time.NewTicker(t.rescanSRVInterval) @@ -569,13 +589,6 @@ func (t *Topology) pollSRVRecords() { } }() - // remove the scheme - uri := t.cfg.uri[14:] - hosts := uri - if idx := strings.IndexAny(uri, "/?@"); idx != -1 { - hosts = uri[:idx] - } - for { select { case <-pollTicker.C: @@ -588,7 +601,7 @@ func (t *Topology) pollSRVRecords() { break } - parsedHosts, err := t.dnsResolver.ParseHosts(hosts, t.cfg.srvServiceName, false) + parsedHosts, err := t.dnsResolver.ParseHosts(hosts, t.cfg.SRVServiceName, false) // DNS problem or no verified hosts returned if err != nil || len(parsedHosts) == 0 { if !t.pollHeartbeatTime.Load().(bool) { @@ -646,14 +659,14 @@ func (t *Topology) processSRVResults(parsedHosts []string) bool { // Now that we've removed all the hosts that disappeared from the SRV record, we need to add any // new hosts added to the SRV record. If adding all of the new hosts would increase the number // of servers past srvMaxHosts, shuffle the list of added hosts. - if t.cfg.srvMaxHosts > 0 && len(t.servers)+len(diff.Added) > t.cfg.srvMaxHosts { + if t.cfg.SRVMaxHosts > 0 && len(t.servers)+len(diff.Added) > t.cfg.SRVMaxHosts { random.Shuffle(len(diff.Added), func(i, j int) { diff.Added[i], diff.Added[j] = diff.Added[j], diff.Added[i] }) } // Add all added hosts until the number of servers reaches srvMaxHosts. for _, a := range diff.Added { - if t.cfg.srvMaxHosts > 0 && len(t.servers) >= t.cfg.srvMaxHosts { + if t.cfg.SRVMaxHosts > 0 && len(t.servers) >= t.cfg.SRVMaxHosts { break } addr := address.Address(a).Canonicalize() @@ -753,7 +766,7 @@ func (t *Topology) addServer(addr address.Address) error { return nil } - svr, err := ConnectServer(addr, t.updateCallback, t.id, t.cfg.serverOpts...) + svr, err := ConnectServer(addr, t.updateCallback, t.id, t.cfg.ServerOpts...) if err != nil { return err } @@ -785,8 +798,8 @@ func (t *Topology) publishServerDescriptionChangedEvent(prev description.Server, NewDescription: current, } - if t.cfg.serverMonitor != nil && t.cfg.serverMonitor.ServerDescriptionChanged != nil { - t.cfg.serverMonitor.ServerDescriptionChanged(serverDescriptionChanged) + if t.cfg.ServerMonitor != nil && t.cfg.ServerMonitor.ServerDescriptionChanged != nil { + t.cfg.ServerMonitor.ServerDescriptionChanged(serverDescriptionChanged) } } @@ -797,8 +810,8 @@ func (t *Topology) publishServerClosedEvent(addr address.Address) { TopologyID: t.id, } - if t.cfg.serverMonitor != nil && t.cfg.serverMonitor.ServerClosed != nil { - t.cfg.serverMonitor.ServerClosed(serverClosed) + if t.cfg.ServerMonitor != nil && t.cfg.ServerMonitor.ServerClosed != nil { + t.cfg.ServerMonitor.ServerClosed(serverClosed) } } @@ -810,8 +823,8 @@ func (t *Topology) publishTopologyDescriptionChangedEvent(prev description.Topol NewDescription: current, } - if t.cfg.serverMonitor != nil && t.cfg.serverMonitor.TopologyDescriptionChanged != nil { - t.cfg.serverMonitor.TopologyDescriptionChanged(topologyDescriptionChanged) + if t.cfg.ServerMonitor != nil && t.cfg.ServerMonitor.TopologyDescriptionChanged != nil { + t.cfg.ServerMonitor.TopologyDescriptionChanged(topologyDescriptionChanged) } } @@ -821,8 +834,8 @@ func (t *Topology) publishTopologyOpeningEvent() { TopologyID: t.id, } - if t.cfg.serverMonitor != nil && t.cfg.serverMonitor.TopologyOpening != nil { - t.cfg.serverMonitor.TopologyOpening(topologyOpening) + if t.cfg.ServerMonitor != nil && t.cfg.ServerMonitor.TopologyOpening != nil { + t.cfg.ServerMonitor.TopologyOpening(topologyOpening) } } @@ -832,7 +845,7 @@ func (t *Topology) publishTopologyClosedEvent() { TopologyID: t.id, } - if t.cfg.serverMonitor != nil && t.cfg.serverMonitor.TopologyClosed != nil { - t.cfg.serverMonitor.TopologyClosed(topologyClosed) + if t.cfg.ServerMonitor != nil && t.cfg.ServerMonitor.TopologyClosed != nil { + t.cfg.ServerMonitor.TopologyClosed(topologyClosed) } } diff --git a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology_options.go b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology_options.go index b405739cb..98b71ea38 100644 --- a/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology_options.go +++ b/vendor/go.mongodb.org/mongo-driver/x/mongo/driver/topology/topology_options.go @@ -7,451 +7,338 @@ package topology import ( - "bytes" "crypto/tls" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" - "io/ioutil" + "net/http" "strings" "time" "go.mongodb.org/mongo-driver/event" + "go.mongodb.org/mongo-driver/mongo/description" + "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/x/mongo/driver" "go.mongodb.org/mongo-driver/x/mongo/driver/auth" - "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" + "go.mongodb.org/mongo-driver/x/mongo/driver/ocsp" "go.mongodb.org/mongo-driver/x/mongo/driver/operation" + "go.mongodb.org/mongo-driver/x/mongo/driver/session" ) -// Option is a configuration option for a topology. -type Option func(*config) error - -type config struct { - mode MonitorMode - replicaSetName string - seedList []string - serverOpts []ServerOption - cs connstring.ConnString // This must not be used for any logic in topology.Topology. - uri string - serverSelectionTimeout time.Duration - serverMonitor *event.ServerMonitor - srvMaxHosts int - srvServiceName string - loadBalanced bool +const defaultServerSelectionTimeout = 30 * time.Second + +// Config is used to construct a topology. +type Config struct { + Mode MonitorMode + ReplicaSetName string + SeedList []string + ServerOpts []ServerOption + URI string + ServerSelectionTimeout time.Duration + ServerMonitor *event.ServerMonitor + SRVMaxHosts int + SRVServiceName string + LoadBalanced bool } -func newConfig(opts ...Option) (*config, error) { - cfg := &config{ - seedList: []string{"localhost:27017"}, - serverSelectionTimeout: 30 * time.Second, +// ConvertToDriverAPIOptions converts a options.ServerAPIOptions instance to a driver.ServerAPIOptions. +func ConvertToDriverAPIOptions(s *options.ServerAPIOptions) *driver.ServerAPIOptions { + driverOpts := driver.NewServerAPIOptions(string(s.ServerAPIVersion)) + if s.Strict != nil { + driverOpts.SetStrict(*s.Strict) } - - for _, opt := range opts { - if opt == nil { - continue - } - err := opt(cfg) - if err != nil { - return nil, err - } + if s.DeprecationErrors != nil { + driverOpts.SetDeprecationErrors(*s.DeprecationErrors) } - - return cfg, nil + return driverOpts } -// WithConnString configures the topology using the connection string. -func WithConnString(fn func(connstring.ConnString) connstring.ConnString) Option { - return func(c *config) error { - cs := fn(c.cs) - c.cs = cs +// NewConfig will translate data from client options into a topology config for building non-default deployments. +// Server and topoplogy options are not honored if a custom deployment is used. +func NewConfig(co *options.ClientOptions, clock *session.ClusterClock) (*Config, error) { + var serverAPI *driver.ServerAPIOptions - if cs.ServerSelectionTimeoutSet { - c.serverSelectionTimeout = cs.ServerSelectionTimeout - } - - var connOpts []ConnectionOption - - if cs.AppName != "" { - c.serverOpts = append(c.serverOpts, WithServerAppName(func(string) string { return cs.AppName })) - } - - if cs.Connect == connstring.SingleConnect || (cs.DirectConnectionSet && cs.DirectConnection) { - c.mode = SingleMode - } + if err := co.Validate(); err != nil { + return nil, err + } - c.seedList = cs.Hosts + var connOpts []ConnectionOption + var serverOpts []ServerOption - if cs.ConnectTimeout > 0 { - c.serverOpts = append(c.serverOpts, WithHeartbeatTimeout(func(time.Duration) time.Duration { return cs.ConnectTimeout })) - connOpts = append(connOpts, WithConnectTimeout(func(time.Duration) time.Duration { return cs.ConnectTimeout })) - } + cfgp := new(Config) - if cs.SocketTimeoutSet { - connOpts = append( - connOpts, - WithReadTimeout(func(time.Duration) time.Duration { return cs.SocketTimeout }), - WithWriteTimeout(func(time.Duration) time.Duration { return cs.SocketTimeout }), - ) - } + // Set the default "ServerSelectionTimeout" to 30 seconds. + cfgp.ServerSelectionTimeout = defaultServerSelectionTimeout - if cs.HeartbeatInterval > 0 { - c.serverOpts = append(c.serverOpts, WithHeartbeatInterval(func(time.Duration) time.Duration { return cs.HeartbeatInterval })) - } + // Set the default "SeedList" to localhost. + cfgp.SeedList = []string{"localhost:27017"} - if cs.MaxConnIdleTime > 0 { - connOpts = append(connOpts, WithIdleTimeout(func(time.Duration) time.Duration { return cs.MaxConnIdleTime })) - } + // TODO(GODRIVER-814): Add tests for topology, server, and connection related options. - if cs.MaxPoolSizeSet { - c.serverOpts = append(c.serverOpts, WithMaxConnections(func(uint64) uint64 { return cs.MaxPoolSize })) - } + // ServerAPIOptions need to be handled early as other client and server options below reference + // c.serverAPI and serverOpts.serverAPI. + if co.ServerAPIOptions != nil { + serverAPI = ConvertToDriverAPIOptions(co.ServerAPIOptions) + serverOpts = append(serverOpts, WithServerAPI(func(*driver.ServerAPIOptions) *driver.ServerAPIOptions { + return serverAPI + })) + } - if cs.MinPoolSizeSet { - c.serverOpts = append(c.serverOpts, WithMinConnections(func(u uint64) uint64 { return cs.MinPoolSize })) - } + cfgp.URI = co.GetURI() - if cs.ReplicaSet != "" { - c.replicaSetName = cs.ReplicaSet - } - - var x509Username string - if cs.SSL { - tlsConfig := new(tls.Config) + if co.SRVServiceName != nil { + cfgp.SRVServiceName = *co.SRVServiceName + } - if cs.SSLCaFileSet { - err := addCACertFromFile(tlsConfig, cs.SSLCaFile) - if err != nil { - return err - } - } + if co.SRVMaxHosts != nil { + cfgp.SRVMaxHosts = *co.SRVMaxHosts + } - if cs.SSLInsecure { - tlsConfig.InsecureSkipVerify = true - } + // AppName + var appName string + if co.AppName != nil { + appName = *co.AppName - if cs.SSLClientCertificateKeyFileSet { - var keyPasswd string - if cs.SSLClientCertificateKeyPasswordSet && cs.SSLClientCertificateKeyPassword != nil { - keyPasswd = cs.SSLClientCertificateKeyPassword() - } - s, err := addClientCertFromFile(tlsConfig, cs.SSLClientCertificateKeyFile, keyPasswd) - if err != nil { - return err - } - - // The Go x509 package gives the subject with the pairs in reverse order that we want. - pairs := strings.Split(s, ",") - b := bytes.NewBufferString("") - - for i := len(pairs) - 1; i >= 0; i-- { - b.WriteString(pairs[i]) - - if i > 0 { - b.WriteString(",") - } - } - - x509Username = b.String() + serverOpts = append(serverOpts, WithServerAppName(func(string) string { + return appName + })) + } + // Compressors & ZlibLevel + var comps []string + if len(co.Compressors) > 0 { + comps = co.Compressors + + connOpts = append(connOpts, WithCompressors( + func(compressors []string) []string { + return append(compressors, comps...) + }, + )) + + for _, comp := range comps { + switch comp { + case "zlib": + connOpts = append(connOpts, WithZlibLevel(func(level *int) *int { + return co.ZlibLevel + })) + case "zstd": + connOpts = append(connOpts, WithZstdLevel(func(level *int) *int { + return co.ZstdLevel + })) } - - connOpts = append(connOpts, WithTLSConfig(func(*tls.Config) *tls.Config { return tlsConfig })) } - if cs.Username != "" || cs.AuthMechanism == auth.MongoDBX509 || cs.AuthMechanism == auth.GSSAPI { - cred := &auth.Cred{ - Source: "admin", - Username: cs.Username, - Password: cs.Password, - PasswordSet: cs.PasswordSet, - Props: cs.AuthMechanismProperties, - } - - if cs.AuthSource != "" { - cred.Source = cs.AuthSource - } else { - switch cs.AuthMechanism { - case auth.MongoDBX509: - if cred.Username == "" { - cred.Username = x509Username - } - fallthrough - case auth.GSSAPI, auth.PLAIN: - cred.Source = "$external" - default: - cred.Source = cs.Database - } - } + serverOpts = append(serverOpts, WithCompressionOptions( + func(opts ...string) []string { return append(opts, comps...) }, + )) + } - authenticator, err := auth.CreateAuthenticator(cs.AuthMechanism, cred) - if err != nil { - return err - } + var loadBalanced bool + if co.LoadBalanced != nil { + loadBalanced = *co.LoadBalanced + } - connOpts = append(connOpts, WithHandshaker(func(h Handshaker) Handshaker { - options := &auth.HandshakeOptions{ - AppName: cs.AppName, - Authenticator: authenticator, - Compressors: cs.Compressors, - LoadBalanced: cs.LoadBalancedSet && cs.LoadBalanced, - } - if cs.AuthMechanism == "" { - // Required for SASL mechanism negotiation during handshake - options.DBUser = cred.Source + "." + cred.Username - } - return auth.Handshaker(h, options) - })) - } else { - // We need to add a non-auth Handshaker to the connection options - connOpts = append(connOpts, WithHandshaker(func(h driver.Handshaker) driver.Handshaker { - return operation.NewHello(). - AppName(cs.AppName). - Compressors(cs.Compressors). - LoadBalanced(cs.LoadBalancedSet && cs.LoadBalanced) - })) + // Handshaker + var handshaker = func(driver.Handshaker) driver.Handshaker { + return operation.NewHello().AppName(appName).Compressors(comps).ClusterClock(clock). + ServerAPI(serverAPI).LoadBalanced(loadBalanced) + } + // Auth & Database & Password & Username + if co.Auth != nil { + cred := &auth.Cred{ + Username: co.Auth.Username, + Password: co.Auth.Password, + PasswordSet: co.Auth.PasswordSet, + Props: co.Auth.AuthMechanismProperties, + Source: co.Auth.AuthSource, } - - if len(cs.Compressors) > 0 { - connOpts = append(connOpts, WithCompressors(func(compressors []string) []string { - return append(compressors, cs.Compressors...) - })) - - for _, comp := range cs.Compressors { - switch comp { - case "zlib": - connOpts = append(connOpts, WithZlibLevel(func(level *int) *int { - return &cs.ZlibLevel - })) - case "zstd": - connOpts = append(connOpts, WithZstdLevel(func(level *int) *int { - return &cs.ZstdLevel - })) - } + mechanism := co.Auth.AuthMechanism + + if len(cred.Source) == 0 { + switch strings.ToUpper(mechanism) { + case auth.MongoDBX509, auth.GSSAPI, auth.PLAIN: + cred.Source = "$external" + default: + cred.Source = "admin" } + } - c.serverOpts = append(c.serverOpts, WithCompressionOptions(func(opts ...string) []string { - return append(opts, cs.Compressors...) - })) + authenticator, err := auth.CreateAuthenticator(mechanism, cred) + if err != nil { + return nil, err } - // LoadBalanced - if cs.LoadBalancedSet { - c.loadBalanced = cs.LoadBalanced - c.serverOpts = append(c.serverOpts, WithServerLoadBalanced(func(bool) bool { - return cs.LoadBalanced - })) - connOpts = append(connOpts, WithConnectionLoadBalanced(func(bool) bool { - return cs.LoadBalanced - })) + handshakeOpts := &auth.HandshakeOptions{ + AppName: appName, + Authenticator: authenticator, + Compressors: comps, + ServerAPI: serverAPI, + LoadBalanced: loadBalanced, + ClusterClock: clock, + HTTPClient: co.HTTPClient, } - if len(connOpts) > 0 { - c.serverOpts = append(c.serverOpts, WithConnectionOptions(func(opts ...ConnectionOption) []ConnectionOption { - return append(opts, connOpts...) - })) + if mechanism == "" { + // Required for SASL mechanism negotiation during handshake + handshakeOpts.DBUser = cred.Source + "." + cred.Username + } + if co.AuthenticateToAnything != nil && *co.AuthenticateToAnything { + // Authenticate arbiters + handshakeOpts.PerformAuthentication = func(serv description.Server) bool { + return true + } } - return nil + handshaker = func(driver.Handshaker) driver.Handshaker { + return auth.Handshaker(nil, handshakeOpts) + } } -} - -// WithMode configures the topology's monitor mode. -func WithMode(fn func(MonitorMode) MonitorMode) Option { - return func(cfg *config) error { - cfg.mode = fn(cfg.mode) - return nil + connOpts = append(connOpts, WithHandshaker(handshaker)) + // ConnectTimeout + if co.ConnectTimeout != nil { + serverOpts = append(serverOpts, WithHeartbeatTimeout( + func(time.Duration) time.Duration { return *co.ConnectTimeout }, + )) + connOpts = append(connOpts, WithConnectTimeout( + func(time.Duration) time.Duration { return *co.ConnectTimeout }, + )) } -} - -// WithReplicaSetName configures the topology's default replica set name. -func WithReplicaSetName(fn func(string) string) Option { - return func(cfg *config) error { - cfg.replicaSetName = fn(cfg.replicaSetName) - return nil + // Dialer + if co.Dialer != nil { + connOpts = append(connOpts, WithDialer( + func(Dialer) Dialer { return co.Dialer }, + )) } -} - -// WithSeedList configures a topology's seed list. -func WithSeedList(fn func(...string) []string) Option { - return func(cfg *config) error { - cfg.seedList = fn(cfg.seedList...) - return nil + // Direct + if co.Direct != nil && *co.Direct { + cfgp.Mode = SingleMode } -} -// WithServerOptions configures a topology's server options for when a new server -// needs to be created. -func WithServerOptions(fn func(...ServerOption) []ServerOption) Option { - return func(cfg *config) error { - cfg.serverOpts = fn(cfg.serverOpts...) - return nil + // HeartbeatInterval + if co.HeartbeatInterval != nil { + serverOpts = append(serverOpts, WithHeartbeatInterval( + func(time.Duration) time.Duration { return *co.HeartbeatInterval }, + )) } -} - -// WithServerSelectionTimeout configures a topology's server selection timeout. -// A server selection timeout of 0 means there is no timeout for server selection. -func WithServerSelectionTimeout(fn func(time.Duration) time.Duration) Option { - return func(cfg *config) error { - cfg.serverSelectionTimeout = fn(cfg.serverSelectionTimeout) - return nil + // Hosts + cfgp.SeedList = []string{"localhost:27017"} // default host + if len(co.Hosts) > 0 { + cfgp.SeedList = co.Hosts } -} -// WithTopologyServerMonitor configures the monitor for all SDAM events -func WithTopologyServerMonitor(fn func(*event.ServerMonitor) *event.ServerMonitor) Option { - return func(cfg *config) error { - cfg.serverMonitor = fn(cfg.serverMonitor) - return nil + // MaxConIdleTime + if co.MaxConnIdleTime != nil { + connOpts = append(connOpts, WithIdleTimeout( + func(time.Duration) time.Duration { return *co.MaxConnIdleTime }, + )) } -} - -// WithURI specifies the URI that was used to create the topology. -func WithURI(fn func(string) string) Option { - return func(cfg *config) error { - cfg.uri = fn(cfg.uri) - return nil + // MaxPoolSize + if co.MaxPoolSize != nil { + serverOpts = append( + serverOpts, + WithMaxConnections(func(uint64) uint64 { return *co.MaxPoolSize }), + ) } -} - -// WithLoadBalanced specifies whether or not the cluster is behind a load balancer. -func WithLoadBalanced(fn func(bool) bool) Option { - return func(cfg *config) error { - cfg.loadBalanced = fn(cfg.loadBalanced) - return nil + // MinPoolSize + if co.MinPoolSize != nil { + serverOpts = append( + serverOpts, + WithMinConnections(func(uint64) uint64 { return *co.MinPoolSize }), + ) } -} - -// WithSRVMaxHosts specifies the SRV host limit that was used to create the topology. -func WithSRVMaxHosts(fn func(int) int) Option { - return func(cfg *config) error { - cfg.srvMaxHosts = fn(cfg.srvMaxHosts) - return nil + // MaxConnecting + if co.MaxConnecting != nil { + serverOpts = append( + serverOpts, + WithMaxConnecting(func(uint64) uint64 { return *co.MaxConnecting }), + ) } -} - -// WithSRVServiceName specifies the SRV service name that was used to create the topology. -func WithSRVServiceName(fn func(string) string) Option { - return func(cfg *config) error { - cfg.srvServiceName = fn(cfg.srvServiceName) - return nil + // PoolMonitor + if co.PoolMonitor != nil { + serverOpts = append( + serverOpts, + WithConnectionPoolMonitor(func(*event.PoolMonitor) *event.PoolMonitor { return co.PoolMonitor }), + ) } -} - -// addCACertFromFile adds a root CA certificate to the configuration given a path -// to the containing file. -func addCACertFromFile(cfg *tls.Config, file string) error { - data, err := ioutil.ReadFile(file) - if err != nil { - return err + // Monitor + if co.Monitor != nil { + connOpts = append(connOpts, WithMonitor( + func(*event.CommandMonitor) *event.CommandMonitor { return co.Monitor }, + )) } - - certBytes, err := loadCert(data) - if err != nil { - return err + // ServerMonitor + if co.ServerMonitor != nil { + serverOpts = append( + serverOpts, + WithServerMonitor(func(*event.ServerMonitor) *event.ServerMonitor { return co.ServerMonitor }), + ) + cfgp.ServerMonitor = co.ServerMonitor } - - cert, err := x509.ParseCertificate(certBytes) - if err != nil { - return err + // ReplicaSet + if co.ReplicaSet != nil { + cfgp.ReplicaSetName = *co.ReplicaSet } - - if cfg.RootCAs == nil { - cfg.RootCAs = x509.NewCertPool() + // ServerSelectionTimeout + if co.ServerSelectionTimeout != nil { + cfgp.ServerSelectionTimeout = *co.ServerSelectionTimeout } - - cfg.RootCAs.AddCert(cert) - - return nil -} - -func loadCert(data []byte) ([]byte, error) { - var certBlock *pem.Block - - for certBlock == nil { - if len(data) == 0 { - return nil, errors.New(".pem file must have both a CERTIFICATE and an RSA PRIVATE KEY section") - } - - block, rest := pem.Decode(data) - if block == nil { - return nil, errors.New("invalid .pem file") - } - - switch block.Type { - case "CERTIFICATE": - if certBlock != nil { - return nil, errors.New("multiple CERTIFICATE sections in .pem file") - } - - certBlock = block - } - - data = rest + // SocketTimeout + if co.SocketTimeout != nil { + connOpts = append( + connOpts, + WithReadTimeout(func(time.Duration) time.Duration { return *co.SocketTimeout }), + WithWriteTimeout(func(time.Duration) time.Duration { return *co.SocketTimeout }), + ) } - - return certBlock.Bytes, nil -} - -// addClientCertFromFile adds a client certificate to the configuration given a path to the -// containing file and returns the certificate's subject name. -func addClientCertFromFile(cfg *tls.Config, clientFile, keyPasswd string) (string, error) { - data, err := ioutil.ReadFile(clientFile) - if err != nil { - return "", err + // TLSConfig + if co.TLSConfig != nil { + connOpts = append(connOpts, WithTLSConfig( + func(*tls.Config) *tls.Config { + return co.TLSConfig + }, + )) } - var currentBlock *pem.Block - var certBlock, certDecodedBlock, keyBlock []byte - - remaining := data - start := 0 - for { - currentBlock, remaining = pem.Decode(remaining) - if currentBlock == nil { - break - } - - if currentBlock.Type == "CERTIFICATE" { - certBlock = data[start : len(data)-len(remaining)] - certDecodedBlock = currentBlock.Bytes - start += len(certBlock) - } else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") { - if keyPasswd != "" && x509.IsEncryptedPEMBlock(currentBlock) { - var encoded bytes.Buffer - buf, err := x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd)) - if err != nil { - return "", err - } - - pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: buf}) - keyBlock = encoded.Bytes() - start = len(data) - len(remaining) - } else { - keyBlock = data[start : len(data)-len(remaining)] - start += len(keyBlock) - } - } - } - if len(certBlock) == 0 { - return "", fmt.Errorf("failed to find CERTIFICATE") + // HTTP Client + if co.HTTPClient != nil { + connOpts = append(connOpts, WithHTTPClient( + func(*http.Client) *http.Client { + return co.HTTPClient + }, + )) } - if len(keyBlock) == 0 { - return "", fmt.Errorf("failed to find PRIVATE KEY") + + // OCSP cache + ocspCache := ocsp.NewCache() + connOpts = append( + connOpts, + WithOCSPCache(func(ocsp.Cache) ocsp.Cache { return ocspCache }), + ) + + // Disable communication with external OCSP responders. + if co.DisableOCSPEndpointCheck != nil { + connOpts = append( + connOpts, + WithDisableOCSPEndpointCheck(func(bool) bool { return *co.DisableOCSPEndpointCheck }), + ) } - cert, err := tls.X509KeyPair(certBlock, keyBlock) - if err != nil { - return "", err + // LoadBalanced + if co.LoadBalanced != nil { + cfgp.LoadBalanced = *co.LoadBalanced + + serverOpts = append( + serverOpts, + WithServerLoadBalanced(func(bool) bool { return *co.LoadBalanced }), + ) + connOpts = append( + connOpts, + WithConnectionLoadBalanced(func(bool) bool { return *co.LoadBalanced }), + ) } - cfg.Certificates = append(cfg.Certificates, cert) + serverOpts = append( + serverOpts, + WithClock(func(*session.ClusterClock) *session.ClusterClock { return clock }), + WithConnectionOptions(func(...ConnectionOption) []ConnectionOption { return connOpts })) - // The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not - // retained. - crt, err := x509.ParseCertificate(certDecodedBlock) - if err != nil { - return "", err - } + cfgp.ServerOpts = serverOpts - return crt.Subject.String(), nil + return cfgp, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 0b14b0939..1799eb708 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -352,8 +352,8 @@ github.com/xdg-go/stringprep # github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d ## explicit github.com/youmark/pkcs8 -# go.mongodb.org/mongo-driver v1.10.2 -## explicit; go 1.10 +# go.mongodb.org/mongo-driver v1.11.0 +## explicit; go 1.13 go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson/bsoncodec go.mongodb.org/mongo-driver/bson/bsonoptions