mongo 2.23.0 → 2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/mongo_console +0 -1
- data/lib/mongo/active_support.rb +1 -2
- data/lib/mongo/address/ipv4.rb +3 -6
- data/lib/mongo/address/ipv6.rb +6 -10
- data/lib/mongo/address/unix.rb +1 -4
- data/lib/mongo/address/validator.rb +16 -28
- data/lib/mongo/address.rb +30 -40
- data/lib/mongo/auth/aws/conversation.rb +6 -10
- data/lib/mongo/auth/aws/credentials.rb +0 -1
- data/lib/mongo/auth/aws/credentials_cache.rb +0 -1
- data/lib/mongo/auth/aws/credentials_retriever.rb +45 -59
- data/lib/mongo/auth/aws/request.rb +20 -35
- data/lib/mongo/auth/aws.rb +1 -2
- data/lib/mongo/auth/base.rb +20 -29
- data/lib/mongo/auth/conversation_base.rb +14 -18
- data/lib/mongo/auth/cr/conversation.rb +0 -3
- data/lib/mongo/auth/cr.rb +1 -4
- data/lib/mongo/auth/credential_cache.rb +0 -2
- data/lib/mongo/auth/gssapi/conversation.rb +3 -8
- data/lib/mongo/auth/gssapi.rb +1 -4
- data/lib/mongo/auth/ldap/conversation.rb +0 -3
- data/lib/mongo/auth/ldap.rb +1 -4
- data/lib/mongo/auth/roles.rb +16 -19
- data/lib/mongo/auth/sasl_conversation_base.rb +7 -11
- data/lib/mongo/auth/scram/conversation.rb +2 -5
- data/lib/mongo/auth/scram.rb +5 -10
- data/lib/mongo/auth/scram256/conversation.rb +2 -5
- data/lib/mongo/auth/scram256.rb +1 -3
- data/lib/mongo/auth/scram_conversation_base.rb +18 -24
- data/lib/mongo/auth/stringprep/profiles/sasl.rb +17 -18
- data/lib/mongo/auth/stringprep/tables.rb +2209 -2210
- data/lib/mongo/auth/stringprep/unicode_normalize/normalize.rb +36 -38
- data/lib/mongo/auth/stringprep/unicode_normalize/tables.rb +1142 -1150
- data/lib/mongo/auth/stringprep.rb +9 -12
- data/lib/mongo/auth/user/view.rb +3 -5
- data/lib/mongo/auth/user.rb +14 -24
- data/lib/mongo/auth/x509/conversation.rb +0 -3
- data/lib/mongo/auth/x509.rb +7 -9
- data/lib/mongo/auth.rb +18 -30
- data/lib/mongo/background_thread.rb +9 -17
- data/lib/mongo/bson.rb +0 -2
- data/lib/mongo/bulk_write/combineable.rb +0 -3
- data/lib/mongo/bulk_write/ordered_combiner.rb +1 -3
- data/lib/mongo/bulk_write/result.rb +20 -17
- data/lib/mongo/bulk_write/result_combiner.rb +17 -13
- data/lib/mongo/bulk_write/transformable.rb +16 -19
- data/lib/mongo/bulk_write/unordered_combiner.rb +1 -3
- data/lib/mongo/bulk_write/validatable.rb +11 -18
- data/lib/mongo/bulk_write.rb +76 -91
- data/lib/mongo/caching_cursor.rb +2 -7
- data/lib/mongo/client.rb +230 -275
- data/lib/mongo/client_encryption.rb +4 -5
- data/lib/mongo/cluster/periodic_executor.rb +2 -5
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +21 -29
- data/lib/mongo/cluster/reapers/socket_reaper.rb +1 -6
- data/lib/mongo/cluster/sdam_flow.rb +136 -159
- data/lib/mongo/cluster/topology/base.rb +15 -18
- data/lib/mongo/cluster/topology/load_balanced.rb +24 -14
- data/lib/mongo/cluster/topology/no_replica_set_options.rb +3 -6
- data/lib/mongo/cluster/topology/replica_set_no_primary.rb +20 -23
- data/lib/mongo/cluster/topology/replica_set_with_primary.rb +0 -2
- data/lib/mongo/cluster/topology/sharded.rb +19 -9
- data/lib/mongo/cluster/topology/single.rb +24 -14
- data/lib/mongo/cluster/topology/unknown.rb +20 -10
- data/lib/mongo/cluster/topology.rb +29 -25
- data/lib/mongo/cluster.rb +148 -183
- data/lib/mongo/cluster_time.rb +14 -31
- data/lib/mongo/collection/helpers.rb +5 -8
- data/lib/mongo/collection/view/aggregation.rb +5 -10
- data/lib/mongo/collection/view/builder/aggregation.rb +6 -9
- data/lib/mongo/collection/view/builder/map_reduce.rb +18 -17
- data/lib/mongo/collection/view/builder.rb +0 -1
- data/lib/mongo/collection/view/change_stream/retryable.rb +3 -8
- data/lib/mongo/collection/view/change_stream.rb +59 -58
- data/lib/mongo/collection/view/explainable.rb +11 -20
- data/lib/mongo/collection/view/immutable.rb +1 -3
- data/lib/mongo/collection/view/iterable.rb +35 -28
- data/lib/mongo/collection/view/map_reduce.rb +20 -25
- data/lib/mongo/collection/view/readable.rb +50 -57
- data/lib/mongo/collection/view/writable.rb +56 -72
- data/lib/mongo/collection/view.rb +9 -8
- data/lib/mongo/collection.rb +63 -76
- data/lib/mongo/condition_variable.rb +4 -4
- data/lib/mongo/config/options.rb +0 -3
- data/lib/mongo/config/validators/option.rb +3 -5
- data/lib/mongo/config.rb +7 -4
- data/lib/mongo/crypt/auto_decryption_context.rb +0 -3
- data/lib/mongo/crypt/auto_encrypter.rb +34 -43
- data/lib/mongo/crypt/auto_encryption_context.rb +0 -3
- data/lib/mongo/crypt/binary.rb +5 -9
- data/lib/mongo/crypt/binding.rb +149 -155
- data/lib/mongo/crypt/context.rb +10 -17
- data/lib/mongo/crypt/data_key_context.rb +2 -7
- data/lib/mongo/crypt/encryption_io.rb +29 -39
- data/lib/mongo/crypt/explicit_decryption_context.rb +0 -3
- data/lib/mongo/crypt/explicit_encrypter.rb +1 -1
- data/lib/mongo/crypt/explicit_encryption_context.rb +19 -30
- data/lib/mongo/crypt/explicit_encryption_expression_context.rb +0 -2
- data/lib/mongo/crypt/handle.rb +42 -48
- data/lib/mongo/crypt/hooks.rb +12 -15
- data/lib/mongo/crypt/kms/aws/credentials.rb +12 -16
- data/lib/mongo/crypt/kms/aws/master_document.rb +6 -9
- data/lib/mongo/crypt/kms/aws.rb +0 -2
- data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +2 -7
- data/lib/mongo/crypt/kms/azure/master_document.rb +15 -19
- data/lib/mongo/crypt/kms/azure.rb +0 -1
- data/lib/mongo/crypt/kms/credentials.rb +13 -27
- data/lib/mongo/crypt/kms/gcp/credentials.rb +12 -14
- data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +7 -9
- data/lib/mongo/crypt/kms/gcp/master_document.rb +12 -16
- data/lib/mongo/crypt/kms/gcp.rb +0 -2
- data/lib/mongo/crypt/kms/kmip/credentials.rb +7 -8
- data/lib/mongo/crypt/kms/kmip/master_document.rb +3 -5
- data/lib/mongo/crypt/kms/kmip.rb +0 -1
- data/lib/mongo/crypt/kms/local/credentials.rb +7 -8
- data/lib/mongo/crypt/kms/local/master_document.rb +2 -6
- data/lib/mongo/crypt/kms/local.rb +0 -1
- data/lib/mongo/crypt/kms/master_key_document.rb +11 -15
- data/lib/mongo/crypt/kms.rb +14 -16
- data/lib/mongo/crypt/kms_context.rb +0 -2
- data/lib/mongo/crypt/rewrap_many_data_key_context.rb +2 -7
- data/lib/mongo/crypt/rewrap_many_data_key_result.rb +2 -4
- data/lib/mongo/crypt/status.rb +12 -14
- data/lib/mongo/crypt.rb +0 -1
- data/lib/mongo/csot_timeout_holder.rb +3 -2
- data/lib/mongo/cursor/kill_spec.rb +7 -10
- data/lib/mongo/cursor.rb +74 -64
- data/lib/mongo/cursor_host.rb +8 -10
- data/lib/mongo/database/view.rb +16 -37
- data/lib/mongo/database.rb +52 -56
- data/lib/mongo/dbref.rb +0 -1
- data/lib/mongo/distinguishing_semaphore.rb +0 -1
- data/lib/mongo/error/auth_error.rb +0 -2
- data/lib/mongo/error/bad_load_balancer_target.rb +0 -2
- data/lib/mongo/error/bulk_write_error.rb +35 -10
- data/lib/mongo/error/change_stream_resumable.rb +0 -2
- data/lib/mongo/error/client_closed.rb +0 -2
- data/lib/mongo/error/closed_stream.rb +1 -4
- data/lib/mongo/error/connection_check_out_timeout.rb +3 -6
- data/lib/mongo/error/connection_perished.rb +0 -2
- data/lib/mongo/error/connection_unavailable.rb +0 -2
- data/lib/mongo/error/credential_check_error.rb +0 -2
- data/lib/mongo/error/crypt_error.rb +0 -2
- data/lib/mongo/error/extra_file_chunk.rb +1 -4
- data/lib/mongo/error/failed_string_prep_validation.rb +5 -6
- data/lib/mongo/error/file_not_found.rb +0 -3
- data/lib/mongo/error/handshake_error.rb +0 -2
- data/lib/mongo/error/insufficient_iteration_count.rb +1 -4
- data/lib/mongo/error/internal_driver_error.rb +0 -2
- data/lib/mongo/error/invalid_address.rb +0 -2
- data/lib/mongo/error/invalid_application_name.rb +0 -3
- data/lib/mongo/error/invalid_bulk_operation.rb +1 -4
- data/lib/mongo/error/invalid_bulk_operation_type.rb +1 -4
- data/lib/mongo/error/invalid_collection_name.rb +1 -4
- data/lib/mongo/error/invalid_config_option.rb +0 -3
- data/lib/mongo/error/invalid_cursor_operation.rb +0 -2
- data/lib/mongo/error/invalid_database_name.rb +1 -4
- data/lib/mongo/error/invalid_document.rb +1 -4
- data/lib/mongo/error/invalid_file.rb +0 -3
- data/lib/mongo/error/invalid_file_revision.rb +0 -3
- data/lib/mongo/error/invalid_min_pool_size.rb +0 -3
- data/lib/mongo/error/invalid_nonce.rb +0 -3
- data/lib/mongo/error/invalid_read_concern.rb +2 -4
- data/lib/mongo/error/invalid_read_option.rb +0 -3
- data/lib/mongo/error/invalid_replacement_document.rb +2 -5
- data/lib/mongo/error/invalid_server_auth_host.rb +0 -2
- data/lib/mongo/error/invalid_server_auth_response.rb +0 -2
- data/lib/mongo/error/invalid_server_preference.rb +10 -16
- data/lib/mongo/error/invalid_session.rb +1 -4
- data/lib/mongo/error/invalid_signature.rb +0 -3
- data/lib/mongo/error/invalid_transaction_operation.rb +5 -8
- data/lib/mongo/error/invalid_txt_record.rb +0 -2
- data/lib/mongo/error/invalid_update_document.rb +2 -5
- data/lib/mongo/error/invalid_uri.rb +1 -4
- data/lib/mongo/error/invalid_write_concern.rb +2 -5
- data/lib/mongo/error/kms_error.rb +0 -2
- data/lib/mongo/error/labelable.rb +0 -3
- data/lib/mongo/error/lint_error.rb +0 -2
- data/lib/mongo/error/max_bson_size.rb +8 -11
- data/lib/mongo/error/max_message_size.rb +2 -5
- data/lib/mongo/error/mismatched_domain.rb +0 -2
- data/lib/mongo/error/missing_connection.rb +0 -2
- data/lib/mongo/error/missing_file_chunk.rb +0 -3
- data/lib/mongo/error/missing_password.rb +0 -2
- data/lib/mongo/error/missing_resume_token.rb +1 -4
- data/lib/mongo/error/missing_scram_server_signature.rb +2 -4
- data/lib/mongo/error/missing_service_id.rb +0 -2
- data/lib/mongo/error/mongocryptd_spawn_error.rb +0 -2
- data/lib/mongo/error/multi_index_drop.rb +0 -3
- data/lib/mongo/error/need_primary_server.rb +0 -2
- data/lib/mongo/error/no_server_available.rb +3 -8
- data/lib/mongo/error/no_service_connection_available.rb +1 -3
- data/lib/mongo/error/no_srv_records.rb +0 -2
- data/lib/mongo/error/notable.rb +8 -16
- data/lib/mongo/error/operation_failure.rb +62 -36
- data/lib/mongo/error/parser.rb +33 -75
- data/lib/mongo/error/pool_cleared_error.rb +1 -3
- data/lib/mongo/error/pool_closed_error.rb +0 -3
- data/lib/mongo/error/pool_error.rb +0 -3
- data/lib/mongo/error/pool_paused_error.rb +0 -2
- data/lib/mongo/error/raise_original_error.rb +1 -3
- data/lib/mongo/error/read_write_retryable.rb +14 -17
- data/lib/mongo/error/sdam_error_detection.rb +3 -5
- data/lib/mongo/error/server_api_conflict.rb +0 -2
- data/lib/mongo/error/server_certificate_revoked.rb +0 -2
- data/lib/mongo/error/server_not_usable.rb +0 -2
- data/lib/mongo/error/session_ended.rb +1 -3
- data/lib/mongo/error/session_not_materialized.rb +1 -3
- data/lib/mongo/error/sessions_not_supported.rb +1 -4
- data/lib/mongo/error/snapshot_session_invalid_server_version.rb +1 -4
- data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +1 -4
- data/lib/mongo/error/socket_error.rb +0 -2
- data/lib/mongo/error/socket_timeout_error.rb +0 -2
- data/lib/mongo/error/transactions_not_supported.rb +3 -6
- data/lib/mongo/error/unchangeable_collection_option.rb +1 -4
- data/lib/mongo/error/unexpected_chunk_length.rb +0 -3
- data/lib/mongo/error/unexpected_response.rb +1 -4
- data/lib/mongo/error/unknown_payload_type.rb +0 -3
- data/lib/mongo/error/unmet_dependency.rb +0 -2
- data/lib/mongo/error/unsupported_array_filters.rb +3 -24
- data/lib/mongo/error/unsupported_collation.rb +3 -24
- data/lib/mongo/error/unsupported_features.rb +0 -2
- data/lib/mongo/error/unsupported_message_type.rb +0 -2
- data/lib/mongo/error/unsupported_option.rb +19 -21
- data/lib/mongo/error/write_retryable.rb +0 -2
- data/lib/mongo/error.rb +10 -24
- data/lib/mongo/event/base.rb +0 -2
- data/lib/mongo/event/listeners.rb +0 -3
- data/lib/mongo/event/publisher.rb +0 -3
- data/lib/mongo/event/subscriber.rb +0 -4
- data/lib/mongo/event.rb +4 -6
- data/lib/mongo/grid/file/chunk.rb +7 -10
- data/lib/mongo/grid/file/info.rb +20 -24
- data/lib/mongo/grid/file.rb +7 -8
- data/lib/mongo/grid/fs_bucket.rb +40 -48
- data/lib/mongo/grid/stream/read.rb +25 -35
- data/lib/mongo/grid/stream/write.rb +17 -22
- data/lib/mongo/grid/stream.rb +2 -4
- data/lib/mongo/grid.rb +0 -1
- data/lib/mongo/id.rb +0 -1
- data/lib/mongo/index/view.rb +49 -48
- data/lib/mongo/index.rb +7 -10
- data/lib/mongo/lint.rb +31 -37
- data/lib/mongo/loggable.rb +5 -8
- data/lib/mongo/logger.rb +1 -7
- data/lib/mongo/monitoring/cmap_log_subscriber.rb +0 -2
- data/lib/mongo/monitoring/command_log_subscriber.rb +25 -33
- data/lib/mongo/monitoring/event/cmap/base.rb +0 -2
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +0 -3
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +2 -5
- data/lib/mongo/monitoring/event/cmap/connection_closed.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/connection_created.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/connection_ready.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +0 -3
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +1 -4
- data/lib/mongo/monitoring/event/cmap/pool_ready.rb +1 -4
- data/lib/mongo/monitoring/event/cmap.rb +0 -1
- data/lib/mongo/monitoring/event/command_failed.rb +5 -9
- data/lib/mongo/monitoring/event/command_started.rb +8 -12
- data/lib/mongo/monitoring/event/command_succeeded.rb +7 -15
- data/lib/mongo/monitoring/event/secure.rb +15 -20
- data/lib/mongo/monitoring/event/server_closed.rb +1 -4
- data/lib/mongo/monitoring/event/server_description_changed.rb +4 -8
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +5 -10
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +1 -4
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +3 -8
- data/lib/mongo/monitoring/event/server_opening.rb +1 -4
- data/lib/mongo/monitoring/event/topology_changed.rb +2 -5
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -4
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -4
- data/lib/mongo/monitoring/event.rb +0 -1
- data/lib/mongo/monitoring/publishable.rb +20 -30
- data/lib/mongo/monitoring/sdam_log_subscriber.rb +0 -2
- data/lib/mongo/monitoring/server_closed_log_subscriber.rb +0 -3
- data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +2 -3
- data/lib/mongo/monitoring/server_opening_log_subscriber.rb +0 -3
- data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +8 -8
- data/lib/mongo/monitoring/topology_closed_log_subscriber.rb +0 -3
- data/lib/mongo/monitoring/topology_opening_log_subscriber.rb +0 -3
- data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +1 -3
- data/lib/mongo/monitoring.rb +38 -39
- data/lib/mongo/operation/aggregate/op_msg.rb +0 -2
- data/lib/mongo/operation/aggregate/result.rb +3 -6
- data/lib/mongo/operation/aggregate.rb +0 -2
- data/lib/mongo/operation/collections_info/result.rb +0 -3
- data/lib/mongo/operation/collections_info.rb +0 -2
- data/lib/mongo/operation/command/op_msg.rb +1 -4
- data/lib/mongo/operation/command.rb +0 -2
- data/lib/mongo/operation/context.rb +13 -16
- data/lib/mongo/operation/count/op_msg.rb +2 -4
- data/lib/mongo/operation/count.rb +0 -2
- data/lib/mongo/operation/create/op_msg.rb +2 -5
- data/lib/mongo/operation/create.rb +0 -2
- data/lib/mongo/operation/create_index/op_msg.rb +3 -7
- data/lib/mongo/operation/create_index.rb +0 -2
- data/lib/mongo/operation/create_user/op_msg.rb +2 -4
- data/lib/mongo/operation/create_user.rb +0 -2
- data/lib/mongo/operation/delete/bulk_result.rb +2 -3
- data/lib/mongo/operation/delete/op_msg.rb +3 -10
- data/lib/mongo/operation/delete/result.rb +0 -3
- data/lib/mongo/operation/delete.rb +1 -5
- data/lib/mongo/operation/distinct/op_msg.rb +2 -5
- data/lib/mongo/operation/distinct.rb +0 -2
- data/lib/mongo/operation/drop/op_msg.rb +0 -2
- data/lib/mongo/operation/drop.rb +0 -2
- data/lib/mongo/operation/drop_database/op_msg.rb +0 -2
- data/lib/mongo/operation/drop_database.rb +0 -2
- data/lib/mongo/operation/drop_index/op_msg.rb +4 -6
- data/lib/mongo/operation/drop_index.rb +0 -2
- data/lib/mongo/operation/explain/op_msg.rb +0 -2
- data/lib/mongo/operation/explain/result.rb +0 -3
- data/lib/mongo/operation/explain.rb +0 -2
- data/lib/mongo/operation/find/builder/command.rb +4 -12
- data/lib/mongo/operation/find/builder/flags.rb +9 -15
- data/lib/mongo/operation/find/builder/modifiers.rb +1 -4
- data/lib/mongo/operation/find/builder.rb +0 -1
- data/lib/mongo/operation/find/op_msg.rb +4 -12
- data/lib/mongo/operation/find/result.rb +0 -3
- data/lib/mongo/operation/find.rb +0 -2
- data/lib/mongo/operation/get_more/command_builder.rb +1 -6
- data/lib/mongo/operation/get_more/op_msg.rb +10 -4
- data/lib/mongo/operation/get_more/result.rb +0 -3
- data/lib/mongo/operation/get_more.rb +0 -2
- data/lib/mongo/operation/indexes/op_msg.rb +0 -2
- data/lib/mongo/operation/indexes/result.rb +1 -5
- data/lib/mongo/operation/indexes.rb +0 -2
- data/lib/mongo/operation/insert/bulk_result.rb +2 -6
- data/lib/mongo/operation/insert/op_msg.rb +2 -4
- data/lib/mongo/operation/insert/result.rb +0 -3
- data/lib/mongo/operation/insert.rb +2 -5
- data/lib/mongo/operation/kill_cursors/command_builder.rb +0 -3
- data/lib/mongo/operation/kill_cursors/op_msg.rb +1 -3
- data/lib/mongo/operation/kill_cursors.rb +0 -2
- data/lib/mongo/operation/list_collections/op_msg.rb +4 -6
- data/lib/mongo/operation/list_collections/result.rb +1 -4
- data/lib/mongo/operation/list_collections.rb +0 -2
- data/lib/mongo/operation/map_reduce/op_msg.rb +0 -2
- data/lib/mongo/operation/map_reduce/result.rb +3 -6
- data/lib/mongo/operation/map_reduce.rb +0 -2
- data/lib/mongo/operation/op_msg_base.rb +0 -1
- data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -5
- data/lib/mongo/operation/parallel_scan/result.rb +2 -5
- data/lib/mongo/operation/parallel_scan.rb +0 -2
- data/lib/mongo/operation/remove_user/op_msg.rb +2 -4
- data/lib/mongo/operation/remove_user.rb +0 -2
- data/lib/mongo/operation/result.rb +38 -47
- data/lib/mongo/operation/shared/bypass_document_validation.rb +3 -7
- data/lib/mongo/operation/shared/causal_consistency_supported.rb +0 -3
- data/lib/mongo/operation/shared/executable.rb +20 -29
- data/lib/mongo/operation/shared/executable_no_validate.rb +0 -3
- data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -2
- data/lib/mongo/operation/shared/idable.rb +3 -6
- data/lib/mongo/operation/shared/limited.rb +0 -3
- data/lib/mongo/operation/shared/object_id_generator.rb +0 -3
- data/lib/mongo/operation/shared/op_msg_executable.rb +0 -2
- data/lib/mongo/operation/shared/polymorphic_lookup.rb +0 -2
- data/lib/mongo/operation/shared/polymorphic_result.rb +2 -4
- data/lib/mongo/operation/shared/read_preference_supported.rb +10 -15
- data/lib/mongo/operation/shared/response_handling.rb +13 -26
- data/lib/mongo/operation/shared/result/aggregatable.rb +12 -13
- data/lib/mongo/operation/shared/sessions_supported.rb +87 -99
- data/lib/mongo/operation/shared/specifiable.rb +32 -58
- data/lib/mongo/operation/shared/write.rb +12 -17
- data/lib/mongo/operation/shared/write_concern_supported.rb +4 -7
- data/lib/mongo/operation/update/bulk_result.rb +13 -17
- data/lib/mongo/operation/update/op_msg.rb +2 -5
- data/lib/mongo/operation/update/result.rb +5 -5
- data/lib/mongo/operation/update.rb +1 -5
- data/lib/mongo/operation/update_user/op_msg.rb +2 -4
- data/lib/mongo/operation/update_user.rb +0 -2
- data/lib/mongo/operation/users_info/op_msg.rb +2 -4
- data/lib/mongo/operation/users_info/result.rb +1 -4
- data/lib/mongo/operation/users_info.rb +0 -2
- data/lib/mongo/operation/write_command/op_msg.rb +2 -10
- data/lib/mongo/operation/write_command.rb +0 -2
- data/lib/mongo/operation.rb +9 -14
- data/lib/mongo/options/mapper.rb +8 -15
- data/lib/mongo/options/redacted.rb +7 -9
- data/lib/mongo/options.rb +0 -1
- data/lib/mongo/protocol/bit_vector.rb +3 -5
- data/lib/mongo/protocol/caching_hash.rb +2 -7
- data/lib/mongo/protocol/compressed.rb +5 -10
- data/lib/mongo/protocol/get_more.rb +2 -8
- data/lib/mongo/protocol/kill_cursors.rb +2 -8
- data/lib/mongo/protocol/message.rb +103 -105
- data/lib/mongo/protocol/msg.rb +48 -63
- data/lib/mongo/protocol/query.rb +32 -41
- data/lib/mongo/protocol/registry.rb +2 -5
- data/lib/mongo/protocol/reply.rb +10 -16
- data/lib/mongo/protocol/serializers.rb +41 -59
- data/lib/mongo/protocol.rb +0 -1
- data/lib/mongo/query_cache.rb +7 -15
- data/lib/mongo/retryable/backpressure.rb +31 -0
- data/lib/mongo/retryable/base_worker.rb +39 -13
- data/lib/mongo/retryable/read_worker.rb +77 -21
- data/lib/mongo/retryable/retry_policy.rb +59 -0
- data/lib/mongo/retryable/write_worker.rb +155 -56
- data/lib/mongo/retryable.rb +70 -9
- data/lib/mongo/search_index/view.rb +1 -1
- data/lib/mongo/semaphore.rb +0 -1
- data/lib/mongo/server/app_metadata/environment.rb +3 -3
- data/lib/mongo/server/app_metadata.rb +4 -5
- data/lib/mongo/server/connection.rb +61 -61
- data/lib/mongo/server/connection_base.rb +43 -53
- data/lib/mongo/server/connection_common.rb +41 -64
- data/lib/mongo/server/connection_pool/generation_manager.rb +6 -11
- data/lib/mongo/server/connection_pool/populator.rb +1 -4
- data/lib/mongo/server/connection_pool.rb +250 -175
- data/lib/mongo/server/description/features.rb +23 -60
- data/lib/mongo/server/description/load_balancer.rb +0 -2
- data/lib/mongo/server/description.rb +138 -137
- data/lib/mongo/server/monitor/app_metadata.rb +3 -4
- data/lib/mongo/server/monitor/connection.rb +28 -35
- data/lib/mongo/server/monitor.rb +65 -60
- data/lib/mongo/server/pending_connection.rb +70 -71
- data/lib/mongo/server/push_monitor/connection.rb +0 -3
- data/lib/mongo/server/push_monitor.rb +21 -29
- data/lib/mongo/server/round_trip_time_calculator.rb +11 -17
- data/lib/mongo/server.rb +60 -93
- data/lib/mongo/server_selector/base.rb +146 -157
- data/lib/mongo/server_selector/nearest.rb +5 -5
- data/lib/mongo/server_selector/primary.rb +4 -5
- data/lib/mongo/server_selector/primary_preferred.rb +5 -6
- data/lib/mongo/server_selector/secondary.rb +5 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +4 -5
- data/lib/mongo/server_selector.rb +3 -4
- data/lib/mongo/session/server_session.rb +6 -7
- data/lib/mongo/session/session_pool.rb +20 -34
- data/lib/mongo/session.rb +321 -189
- data/lib/mongo/socket/ocsp_cache.rb +8 -13
- data/lib/mongo/socket/ocsp_verifier.rb +69 -70
- data/lib/mongo/socket/ssl.rb +44 -43
- data/lib/mongo/socket/tcp.rb +5 -8
- data/lib/mongo/socket/unix.rb +0 -4
- data/lib/mongo/socket.rb +80 -102
- data/lib/mongo/srv/monitor.rb +6 -11
- data/lib/mongo/srv/resolver.rb +15 -24
- data/lib/mongo/srv/result.rb +18 -24
- data/lib/mongo/srv.rb +0 -1
- data/lib/mongo/timeout.rb +4 -11
- data/lib/mongo/topology_version.rb +8 -13
- data/lib/mongo/tracing/open_telemetry/command_tracer.rb +28 -1
- data/lib/mongo/tracing/open_telemetry/operation_tracer.rb +1 -1
- data/lib/mongo/tracing/open_telemetry/tracer.rb +1 -1
- data/lib/mongo/uri/options_mapper.rb +135 -126
- data/lib/mongo/uri/srv_protocol.rb +25 -38
- data/lib/mongo/uri.rb +95 -139
- data/lib/mongo/utils.rb +5 -12
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo/write_concern/acknowledged.rb +0 -2
- data/lib/mongo/write_concern/base.rb +6 -6
- data/lib/mongo/write_concern/unacknowledged.rb +0 -2
- data/lib/mongo/write_concern.rb +14 -15
- data/lib/mongo.rb +2 -3
- data/mongo.gemspec +17 -17
- metadata +5 -5
- data/lib/mongo/error/server_api_not_supported.rb +0 -27
- data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +0 -32
- data/lib/mongo/operation/shared/validatable.rb +0 -87
data/lib/mongo/session.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
# rubocop:todo all
|
|
3
2
|
|
|
4
3
|
# Copyright (C) 2017-2020 MongoDB Inc.
|
|
5
4
|
#
|
|
@@ -19,7 +18,6 @@ require 'mongo/session/session_pool'
|
|
|
19
18
|
require 'mongo/session/server_session'
|
|
20
19
|
|
|
21
20
|
module Mongo
|
|
22
|
-
|
|
23
21
|
# A logical session representing a set of sequential operations executed
|
|
24
22
|
# by an application that are related in some way.
|
|
25
23
|
#
|
|
@@ -36,10 +34,9 @@ module Mongo
|
|
|
36
34
|
# Initialize a Session.
|
|
37
35
|
#
|
|
38
36
|
# A session can be explicit or implicit. Lifetime of explicit sessions is
|
|
39
|
-
# managed by the application - applications
|
|
37
|
+
# managed by the application - applications explicitly create such sessions
|
|
40
38
|
# and explicitly end them. Implicit sessions are created automatically by
|
|
41
|
-
# the driver
|
|
42
|
-
# (3.6+), and their lifetime is managed by the driver.
|
|
39
|
+
# the driver, and their lifetime is managed by the driver.
|
|
43
40
|
#
|
|
44
41
|
# When an implicit session is created, it cannot have a server session
|
|
45
42
|
# associated with it. The server session will be checked out of the
|
|
@@ -77,6 +74,8 @@ module Mongo
|
|
|
77
74
|
# and *:nearest*.
|
|
78
75
|
# @option options [ true | false ] :snapshot Set up the session for
|
|
79
76
|
# snapshot reads.
|
|
77
|
+
# @option options [ BSON::Timestamp ] :snapshot_time The desired snapshot
|
|
78
|
+
# time for snapshot reads. Only valid when :snapshot is true.
|
|
80
79
|
#
|
|
81
80
|
# @since 2.5.0
|
|
82
81
|
# @api private
|
|
@@ -85,24 +84,37 @@ module Mongo
|
|
|
85
84
|
raise ArgumentError, ':causal_consistency and :snapshot options cannot be both set on a session'
|
|
86
85
|
end
|
|
87
86
|
|
|
87
|
+
if options[:snapshot_time] && !options[:snapshot]
|
|
88
|
+
raise ArgumentError, ':snapshot_time can only be set when :snapshot is true'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if options[:snapshot_time] && !options[:snapshot_time].is_a?(BSON::Timestamp)
|
|
92
|
+
raise ArgumentError, ':snapshot_time must be a BSON::Timestamp'
|
|
93
|
+
end
|
|
94
|
+
|
|
88
95
|
if options[:implicit]
|
|
89
96
|
unless server_session.nil?
|
|
90
97
|
raise ArgumentError, 'Implicit session cannot reference server session during construction'
|
|
91
98
|
end
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
raise ArgumentError, 'Explicit session must reference server session during construction'
|
|
95
|
-
end
|
|
99
|
+
elsif server_session.nil?
|
|
100
|
+
raise ArgumentError, 'Explicit session must reference server session during construction'
|
|
96
101
|
end
|
|
97
102
|
|
|
98
103
|
@server_session = server_session
|
|
99
104
|
options = options.dup
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
# Implicit sessions only need the cluster and client options (never run
|
|
107
|
+
# transactions), so avoid creating a Mongo::Client clone to prevent
|
|
108
|
+
# memory leaks: use the original client directly instead.
|
|
109
|
+
@client = options[:implicit] ? client : client.use(:admin)
|
|
110
|
+
@cluster = @client.cluster
|
|
102
111
|
@options = options.dup.freeze
|
|
103
112
|
@cluster_time = nil
|
|
104
113
|
@state = NO_TRANSACTION_STATE
|
|
105
114
|
@with_transaction_deadline = nil
|
|
115
|
+
@with_transaction_timeout_ms = nil
|
|
116
|
+
@inside_with_transaction = false
|
|
117
|
+
@snapshot_timestamp = options[:snapshot_time]
|
|
106
118
|
end
|
|
107
119
|
|
|
108
120
|
# @return [ Hash ] The options for this session.
|
|
@@ -115,9 +127,7 @@ module Mongo
|
|
|
115
127
|
# @since 2.5.1
|
|
116
128
|
attr_reader :client
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
@client.cluster
|
|
120
|
-
end
|
|
130
|
+
attr_reader :cluster
|
|
121
131
|
|
|
122
132
|
# @return [ true | false ] Whether the session is configured for snapshot
|
|
123
133
|
# reads.
|
|
@@ -154,7 +164,7 @@ module Mongo
|
|
|
154
164
|
#
|
|
155
165
|
# @since 2.6.0
|
|
156
166
|
def txn_options
|
|
157
|
-
@txn_options or raise ArgumentError,
|
|
167
|
+
@txn_options or raise ArgumentError, 'There is no active transaction'
|
|
158
168
|
end
|
|
159
169
|
|
|
160
170
|
# Is this session an implicit one (not user-created).
|
|
@@ -208,8 +218,8 @@ module Mongo
|
|
|
208
218
|
#
|
|
209
219
|
# @return [ true, false ] If writes will be retried.
|
|
210
220
|
#
|
|
211
|
-
# @note Retryable writes are only available
|
|
212
|
-
#
|
|
221
|
+
# @note Retryable writes are only available with sharded clusters, replica
|
|
222
|
+
# sets, or load-balanced topologies.
|
|
213
223
|
#
|
|
214
224
|
# @since 2.5.0
|
|
215
225
|
def retry_writes?
|
|
@@ -229,7 +239,7 @@ module Mongo
|
|
|
229
239
|
# @since 2.6.0
|
|
230
240
|
def txn_read_preference
|
|
231
241
|
rp = txn_options[:read] ||
|
|
232
|
-
|
|
242
|
+
@client.read_preference
|
|
233
243
|
Mongo::Lint.validate_underscore_read_preference(rp)
|
|
234
244
|
rp
|
|
235
245
|
end
|
|
@@ -255,9 +265,7 @@ module Mongo
|
|
|
255
265
|
#
|
|
256
266
|
# @since 2.5.0
|
|
257
267
|
def session_id
|
|
258
|
-
if ended?
|
|
259
|
-
raise Error::SessionEnded
|
|
260
|
-
end
|
|
268
|
+
raise Error::SessionEnded if ended?
|
|
261
269
|
|
|
262
270
|
# An explicit session will always have a session_id, because during
|
|
263
271
|
# construction a server session must be provided. An implicit session
|
|
@@ -266,9 +274,7 @@ module Mongo
|
|
|
266
274
|
# to experience this failure because an implicit session shouldn't be
|
|
267
275
|
# accessible to applications due to its lifetime being constrained to
|
|
268
276
|
# operation execution, which is done entirely by the driver.
|
|
269
|
-
unless materialized?
|
|
270
|
-
raise Error::SessionNotMaterialized
|
|
271
|
-
end
|
|
277
|
+
raise Error::SessionNotMaterialized unless materialized?
|
|
272
278
|
|
|
273
279
|
@server_session.session_id
|
|
274
280
|
end
|
|
@@ -296,20 +302,20 @@ module Mongo
|
|
|
296
302
|
#
|
|
297
303
|
# @since 2.5.0
|
|
298
304
|
MISMATCHED_CLUSTER_ERROR_MSG = 'The configuration of the client used to create this session does not match that ' +
|
|
299
|
-
|
|
300
|
-
|
|
305
|
+
'of the client owning this operation. Please only use this session for operations through its parent ' +
|
|
306
|
+
'client.'
|
|
301
307
|
|
|
302
308
|
# Error message describing that the session cannot be used because it has already been ended.
|
|
303
309
|
#
|
|
304
310
|
# @since 2.5.0
|
|
305
|
-
SESSION_ENDED_ERROR_MSG = 'This session has ended and cannot be used. Please create a new one.'
|
|
311
|
+
SESSION_ENDED_ERROR_MSG = 'This session has ended and cannot be used. Please create a new one.'
|
|
306
312
|
|
|
307
313
|
# Error message describing that sessions are not supported by the server version.
|
|
308
314
|
#
|
|
309
315
|
# @since 2.5.0
|
|
310
316
|
# @deprecated
|
|
311
|
-
SESSIONS_NOT_SUPPORTED = 'Sessions are not supported by the connected servers.'
|
|
312
|
-
#
|
|
317
|
+
SESSIONS_NOT_SUPPORTED = 'Sessions are not supported by the connected servers.'
|
|
318
|
+
# NOTE: SESSIONS_NOT_SUPPORTED is used by Mongoid 7.6 and earlier
|
|
313
319
|
|
|
314
320
|
# The state of a session in which the last operation was not related to
|
|
315
321
|
# any transaction or no operations have yet occurred.
|
|
@@ -384,13 +390,15 @@ module Mongo
|
|
|
384
390
|
rescue Mongo::Error, Error::AuthError
|
|
385
391
|
end
|
|
386
392
|
end
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
393
|
+
# Release any pinned connection (e.g. after a committed transaction
|
|
394
|
+
# in load-balanced mode).
|
|
395
|
+
unpin if pinned_connection_global_id
|
|
396
|
+
cluster.session_pool.checkin(@server_session) if @server_session
|
|
390
397
|
end
|
|
391
398
|
ensure
|
|
392
399
|
@server_session = nil
|
|
393
400
|
@ended = true
|
|
401
|
+
@client = nil
|
|
394
402
|
end
|
|
395
403
|
|
|
396
404
|
# Executes the provided block in a transaction, retrying as necessary.
|
|
@@ -448,38 +456,74 @@ module Mongo
|
|
|
448
456
|
#
|
|
449
457
|
# @since 2.7.0
|
|
450
458
|
def with_transaction(options = nil)
|
|
459
|
+
@inside_with_transaction = true
|
|
460
|
+
@with_transaction_timeout_ms = options&.dig(:timeout_ms) || @options[:default_timeout_ms] || @client.timeout_ms
|
|
451
461
|
@with_transaction_deadline = calculate_with_transaction_deadline(options)
|
|
452
462
|
deadline = if @with_transaction_deadline
|
|
453
463
|
# CSOT enabled, so we have a customer defined deadline.
|
|
454
464
|
@with_transaction_deadline
|
|
455
465
|
else
|
|
456
|
-
|
|
466
|
+
# CSOT not enabled, so we use the default deadline, 120 seconds.
|
|
457
467
|
Utils.monotonic_time + 120
|
|
458
468
|
end
|
|
459
469
|
transaction_in_progress = false
|
|
470
|
+
transaction_attempt = 0
|
|
471
|
+
last_error = nil
|
|
472
|
+
overload_error_count = 0
|
|
473
|
+
overload_encountered = false
|
|
474
|
+
|
|
460
475
|
loop do
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
476
|
+
if transaction_attempt > 0
|
|
477
|
+
if overload_encountered
|
|
478
|
+
delay = @client.retry_policy.backoff_delay(overload_error_count)
|
|
479
|
+
if backoff_would_exceed_deadline?(deadline, delay)
|
|
480
|
+
make_timeout_error_from(last_error, 'CSOT timeout expired waiting to retry withTransaction')
|
|
481
|
+
end
|
|
482
|
+
raise(last_error) unless @client.retry_policy.should_retry_overload?(overload_error_count, delay)
|
|
483
|
+
|
|
484
|
+
sleep(delay)
|
|
485
|
+
else
|
|
486
|
+
backoff = backoff_seconds_for_retry(transaction_attempt)
|
|
487
|
+
if backoff_would_exceed_deadline?(deadline, backoff)
|
|
488
|
+
make_timeout_error_from(last_error, 'CSOT timeout expired waiting to retry withTransaction')
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
sleep(backoff)
|
|
492
|
+
end
|
|
464
493
|
end
|
|
494
|
+
|
|
495
|
+
commit_options = {}
|
|
496
|
+
commit_options[:write_concern] = options[:write_concern] if options
|
|
465
497
|
start_transaction(options)
|
|
466
498
|
transaction_in_progress = true
|
|
499
|
+
transaction_attempt += 1
|
|
500
|
+
|
|
467
501
|
begin
|
|
468
502
|
rv = yield self
|
|
469
503
|
rescue Exception => e
|
|
470
504
|
if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
|
|
471
505
|
log_warn("Aborting transaction due to #{e.class}: #{e}")
|
|
472
|
-
|
|
506
|
+
# CSOT: if the deadline is already expired, clear it so that
|
|
507
|
+
# abort_transaction uses a fresh timeout (not the expired deadline).
|
|
508
|
+
# If the deadline is not yet expired, keep it so abort uses remaining time.
|
|
509
|
+
@with_transaction_deadline = nil if @with_transaction_deadline && deadline_expired?(deadline)
|
|
473
510
|
abort_transaction
|
|
474
511
|
transaction_in_progress = false
|
|
475
512
|
end
|
|
476
513
|
|
|
477
514
|
if deadline_expired?(deadline)
|
|
478
515
|
transaction_in_progress = false
|
|
479
|
-
|
|
516
|
+
make_timeout_error_from(e, 'CSOT timeout expired during withTransaction callback')
|
|
480
517
|
end
|
|
481
518
|
|
|
482
519
|
if e.is_a?(Mongo::Error) && e.label?('TransientTransactionError')
|
|
520
|
+
last_error = e
|
|
521
|
+
if e.label?('SystemOverloadedError')
|
|
522
|
+
overload_encountered = true
|
|
523
|
+
overload_error_count += 1
|
|
524
|
+
elsif overload_encountered
|
|
525
|
+
overload_error_count += 1
|
|
526
|
+
end
|
|
483
527
|
next
|
|
484
528
|
end
|
|
485
529
|
|
|
@@ -490,32 +534,71 @@ module Mongo
|
|
|
490
534
|
return rv
|
|
491
535
|
end
|
|
492
536
|
|
|
537
|
+
# CSOT: if the timeout has expired before we can commit, abort the
|
|
538
|
+
# transaction instead and raise a client-side timeout error.
|
|
539
|
+
if @with_transaction_deadline && deadline_expired?(deadline)
|
|
540
|
+
transaction_in_progress = false
|
|
541
|
+
@with_transaction_deadline = nil
|
|
542
|
+
abort_transaction
|
|
543
|
+
raise Mongo::Error::TimeoutError, 'CSOT timeout expired before transaction could be committed'
|
|
544
|
+
end
|
|
545
|
+
|
|
493
546
|
begin
|
|
494
547
|
commit_transaction(commit_options)
|
|
495
548
|
transaction_in_progress = false
|
|
496
549
|
return rv
|
|
497
550
|
rescue Mongo::Error => e
|
|
498
551
|
if e.label?('UnknownTransactionCommitResult')
|
|
499
|
-
if
|
|
500
|
-
|
|
501
|
-
then
|
|
552
|
+
if deadline_expired?(deadline) ||
|
|
553
|
+
(e.is_a?(Error::OperationFailure::Family) && e.max_time_ms_expired?)
|
|
502
554
|
transaction_in_progress = false
|
|
503
|
-
|
|
555
|
+
|
|
556
|
+
raise unless @with_transaction_timeout_ms && deadline_expired?(deadline)
|
|
557
|
+
|
|
558
|
+
make_timeout_error_from(e, 'CSOT timeout expired during withTransaction commit')
|
|
504
559
|
end
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
560
|
+
|
|
561
|
+
if e.label?('SystemOverloadedError')
|
|
562
|
+
overload_encountered = true
|
|
563
|
+
overload_error_count += 1
|
|
564
|
+
elsif overload_encountered
|
|
565
|
+
overload_error_count += 1
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
if overload_encountered
|
|
569
|
+
delay = @client.retry_policy.backoff_delay(overload_error_count)
|
|
570
|
+
if backoff_would_exceed_deadline?(deadline, delay)
|
|
571
|
+
transaction_in_progress = false
|
|
572
|
+
make_timeout_error_from(e, 'CSOT timeout expired during withTransaction commit')
|
|
512
573
|
end
|
|
574
|
+
unless @client.retry_policy.should_retry_overload?(overload_error_count, delay)
|
|
575
|
+
transaction_in_progress = false
|
|
576
|
+
raise
|
|
577
|
+
end
|
|
578
|
+
sleep(delay)
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
wc_options = case v = commit_options[:write_concern]
|
|
582
|
+
when WriteConcern::Base
|
|
583
|
+
v.options
|
|
584
|
+
when nil
|
|
585
|
+
{}
|
|
586
|
+
else
|
|
587
|
+
v
|
|
588
|
+
end
|
|
513
589
|
commit_options[:write_concern] = wc_options.merge(w: :majority)
|
|
514
590
|
retry
|
|
515
591
|
elsif e.label?('TransientTransactionError')
|
|
516
592
|
if Utils.monotonic_time >= deadline
|
|
517
593
|
transaction_in_progress = false
|
|
518
|
-
|
|
594
|
+
make_timeout_error_from(e, 'CSOT timeout expired during withTransaction commit')
|
|
595
|
+
end
|
|
596
|
+
last_error = e
|
|
597
|
+
if e.label?('SystemOverloadedError')
|
|
598
|
+
overload_encountered = true
|
|
599
|
+
overload_error_count += 1
|
|
600
|
+
elsif overload_encountered
|
|
601
|
+
overload_error_count += 1
|
|
519
602
|
end
|
|
520
603
|
@state = NO_TRANSACTION_STATE
|
|
521
604
|
next
|
|
@@ -542,6 +625,8 @@ module Mongo
|
|
|
542
625
|
end
|
|
543
626
|
end
|
|
544
627
|
@with_transaction_deadline = nil
|
|
628
|
+
@with_transaction_timeout_ms = nil
|
|
629
|
+
@inside_with_transaction = false
|
|
545
630
|
end
|
|
546
631
|
|
|
547
632
|
# Places subsequent operations in this session into a new transaction.
|
|
@@ -556,7 +641,7 @@ module Mongo
|
|
|
556
641
|
#
|
|
557
642
|
# @option options [ Integer ] :max_commit_time_ms The maximum amount of
|
|
558
643
|
# time to allow a single commitTransaction command to run, in milliseconds.
|
|
559
|
-
# This
|
|
644
|
+
# This option is deprecated, use :timeout_ms instead.
|
|
560
645
|
# @option options [ Hash ] :read_concern The read concern options hash,
|
|
561
646
|
# with the following optional keys:
|
|
562
647
|
# - *:level* -- the read preference level as a symbol; valid values
|
|
@@ -582,28 +667,25 @@ module Mongo
|
|
|
582
667
|
if options
|
|
583
668
|
Lint.validate_read_concern_option(options[:read_concern])
|
|
584
669
|
|
|
585
|
-
|
|
586
|
-
#
|
|
587
|
-
#
|
|
588
|
-
#
|
|
589
|
-
mode
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
end
|
|
595
|
-
=end
|
|
670
|
+
# # It would be handy to detect invalid read preferences here, but
|
|
671
|
+
# # some of the spec tests require later detection of invalid read prefs.
|
|
672
|
+
# # Maybe we can do this when lint mode is on.
|
|
673
|
+
# mode = options[:read] && options[:read][:mode].to_s
|
|
674
|
+
# if mode && mode != 'primary'
|
|
675
|
+
# raise Mongo::Error::InvalidTransactionOperation.new(
|
|
676
|
+
# "read preference in a transaction must be primary (requested: #{mode})"
|
|
677
|
+
# )
|
|
678
|
+
# end
|
|
596
679
|
end
|
|
597
680
|
|
|
598
|
-
if snapshot?
|
|
599
|
-
raise Mongo::Error::SnapshotSessionTransactionProhibited
|
|
600
|
-
end
|
|
681
|
+
raise Mongo::Error::SnapshotSessionTransactionProhibited if snapshot?
|
|
601
682
|
|
|
602
683
|
check_if_ended!
|
|
603
684
|
|
|
604
685
|
if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
|
|
605
686
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
606
|
-
Mongo::Error::InvalidTransactionOperation::TRANSACTION_ALREADY_IN_PROGRESS
|
|
687
|
+
Mongo::Error::InvalidTransactionOperation::TRANSACTION_ALREADY_IN_PROGRESS
|
|
688
|
+
)
|
|
607
689
|
end
|
|
608
690
|
|
|
609
691
|
unpin
|
|
@@ -613,7 +695,8 @@ module Mongo
|
|
|
613
695
|
|
|
614
696
|
if txn_write_concern && !WriteConcern.get(txn_write_concern).acknowledged?
|
|
615
697
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
616
|
-
Mongo::Error::InvalidTransactionOperation::UNACKNOWLEDGED_WRITE_CONCERN
|
|
698
|
+
Mongo::Error::InvalidTransactionOperation::UNACKNOWLEDGED_WRITE_CONCERN
|
|
699
|
+
)
|
|
617
700
|
end
|
|
618
701
|
|
|
619
702
|
@state = STARTING_TRANSACTION_STATE
|
|
@@ -642,7 +725,7 @@ module Mongo
|
|
|
642
725
|
# @raise [ Error::InvalidTransactionOperation ] If there is no active transaction.
|
|
643
726
|
#
|
|
644
727
|
# @since 2.6.0
|
|
645
|
-
def commit_transaction(options=nil)
|
|
728
|
+
def commit_transaction(options = nil)
|
|
646
729
|
QueryCache.clear
|
|
647
730
|
check_if_ended!
|
|
648
731
|
check_if_no_transaction!
|
|
@@ -650,7 +733,9 @@ module Mongo
|
|
|
650
733
|
if within_states?(TRANSACTION_ABORTED_STATE)
|
|
651
734
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
652
735
|
Mongo::Error::InvalidTransactionOperation.cannot_call_after_msg(
|
|
653
|
-
:abortTransaction, :commitTransaction
|
|
736
|
+
:abortTransaction, :commitTransaction
|
|
737
|
+
)
|
|
738
|
+
)
|
|
654
739
|
end
|
|
655
740
|
|
|
656
741
|
options ||= {}
|
|
@@ -670,9 +755,7 @@ module Mongo
|
|
|
670
755
|
@committing_transaction = true
|
|
671
756
|
|
|
672
757
|
write_concern = options[:write_concern] || txn_options[:write_concern]
|
|
673
|
-
if write_concern && !write_concern.is_a?(WriteConcern::Base)
|
|
674
|
-
write_concern = WriteConcern.get(write_concern)
|
|
675
|
-
end
|
|
758
|
+
write_concern = WriteConcern.get(write_concern) if write_concern && !write_concern.is_a?(WriteConcern::Base)
|
|
676
759
|
|
|
677
760
|
context = Operation::Context.new(
|
|
678
761
|
client: @client,
|
|
@@ -680,15 +763,14 @@ module Mongo
|
|
|
680
763
|
operation_timeouts: operation_timeouts(options)
|
|
681
764
|
)
|
|
682
765
|
write_with_retry(write_concern, ending_transaction: true,
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if context.retry?
|
|
766
|
+
context: context) do |connection, txn_num, context|
|
|
767
|
+
if context.retry? && !context.overload_only_retry?
|
|
686
768
|
if write_concern
|
|
687
769
|
wco = write_concern.options.merge(w: :majority)
|
|
688
|
-
wco[:wtimeout] ||=
|
|
770
|
+
wco[:wtimeout] ||= 10_000
|
|
689
771
|
write_concern = WriteConcern.get(wco)
|
|
690
772
|
else
|
|
691
|
-
write_concern = WriteConcern.get(w: :majority, wtimeout:
|
|
773
|
+
write_concern = WriteConcern.get(w: :majority, wtimeout: 10_000)
|
|
692
774
|
end
|
|
693
775
|
end
|
|
694
776
|
spec = {
|
|
@@ -738,12 +820,15 @@ module Mongo
|
|
|
738
820
|
if within_states?(TRANSACTION_COMMITTED_STATE)
|
|
739
821
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
740
822
|
Mongo::Error::InvalidTransactionOperation.cannot_call_after_msg(
|
|
741
|
-
:commitTransaction, :abortTransaction
|
|
823
|
+
:commitTransaction, :abortTransaction
|
|
824
|
+
)
|
|
825
|
+
)
|
|
742
826
|
end
|
|
743
827
|
|
|
744
828
|
if within_states?(TRANSACTION_ABORTED_STATE)
|
|
745
829
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
746
|
-
Mongo::Error::InvalidTransactionOperation.cannot_call_twice_msg(:abortTransaction)
|
|
830
|
+
Mongo::Error::InvalidTransactionOperation.cannot_call_twice_msg(:abortTransaction)
|
|
831
|
+
)
|
|
747
832
|
end
|
|
748
833
|
|
|
749
834
|
options ||= {}
|
|
@@ -757,21 +842,18 @@ module Mongo
|
|
|
757
842
|
operation_timeouts: operation_timeouts(options)
|
|
758
843
|
)
|
|
759
844
|
write_with_retry(txn_options[:write_concern],
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
)
|
|
769
|
-
tracer.trace_operation(operation, context, op_name: 'abortTransaction') do
|
|
770
|
-
operation.execute_with_connection(connection, context: context)
|
|
771
|
-
end
|
|
772
|
-
ensure
|
|
773
|
-
unpin
|
|
845
|
+
ending_transaction: true, context: context) do |connection, txn_num, context|
|
|
846
|
+
operation = Operation::Command.new(
|
|
847
|
+
selector: { abortTransaction: 1 },
|
|
848
|
+
db_name: 'admin',
|
|
849
|
+
session: self,
|
|
850
|
+
txn_num: txn_num
|
|
851
|
+
)
|
|
852
|
+
tracer.trace_operation(operation, context, op_name: 'abortTransaction') do
|
|
853
|
+
operation.execute_with_connection(connection, context: context)
|
|
774
854
|
end
|
|
855
|
+
ensure
|
|
856
|
+
unpin
|
|
775
857
|
end
|
|
776
858
|
end
|
|
777
859
|
|
|
@@ -835,14 +917,12 @@ module Mongo
|
|
|
835
917
|
#
|
|
836
918
|
# @api private
|
|
837
919
|
def pin_to_server(server)
|
|
838
|
-
if server.nil?
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
unless server.mongos?
|
|
843
|
-
raise Error::LintError, "Attempted to pin the session to server #{server.summary} which is not a mongos"
|
|
844
|
-
end
|
|
920
|
+
raise ArgumentError, 'Cannot pin to a nil server' if server.nil?
|
|
921
|
+
|
|
922
|
+
if Lint.enabled? && !server.mongos?
|
|
923
|
+
raise Error::LintError, "Attempted to pin the session to server #{server.summary} which is not a mongos"
|
|
845
924
|
end
|
|
925
|
+
|
|
846
926
|
@pinned_server = server
|
|
847
927
|
end
|
|
848
928
|
|
|
@@ -850,13 +930,14 @@ module Mongo
|
|
|
850
930
|
#
|
|
851
931
|
# @param [ Integer ] connection_global_id The global id of connection to pin
|
|
852
932
|
# this session to.
|
|
933
|
+
# @param [ Connection | nil ] connection The connection object to pin to.
|
|
853
934
|
#
|
|
854
935
|
# @api private
|
|
855
|
-
def pin_to_connection(connection_global_id)
|
|
856
|
-
if connection_global_id.nil?
|
|
857
|
-
|
|
858
|
-
end
|
|
936
|
+
def pin_to_connection(connection_global_id, connection: nil)
|
|
937
|
+
raise ArgumentError, 'Cannot pin to a nil connection id' if connection_global_id.nil?
|
|
938
|
+
|
|
859
939
|
@pinned_connection_global_id = connection_global_id
|
|
940
|
+
@pinned_connection = connection
|
|
860
941
|
end
|
|
861
942
|
|
|
862
943
|
# Unpins this session from the pinned server or connection,
|
|
@@ -866,9 +947,25 @@ module Mongo
|
|
|
866
947
|
#
|
|
867
948
|
# @api private
|
|
868
949
|
def unpin(connection = nil)
|
|
950
|
+
# Idempotent: if there is no pinned state to clear, do nothing. Nested
|
|
951
|
+
# unpin_maybe handlers (e.g. in BulkWrite#execute_operation wrapping an
|
|
952
|
+
# OpMsg execution that already calls unpin_maybe in its own do_execute)
|
|
953
|
+
# can call this method twice for the same error; checking the connection
|
|
954
|
+
# back into the pool a second time would raise from the pool.
|
|
955
|
+
return if @pinned_server.nil? && @pinned_connection.nil? && @pinned_connection_global_id.nil?
|
|
956
|
+
|
|
869
957
|
@pinned_server = nil
|
|
870
958
|
@pinned_connection_global_id = nil
|
|
871
|
-
connection
|
|
959
|
+
conn = connection || @pinned_connection
|
|
960
|
+
if conn
|
|
961
|
+
conn.unpin(:transaction)
|
|
962
|
+
# Only check the connection back into the pool if nothing else
|
|
963
|
+
# still holds a pin on it (e.g. an open cursor).
|
|
964
|
+
unless conn.pinned?
|
|
965
|
+
conn.connection_pool.check_in(conn)
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
@pinned_connection = nil
|
|
872
969
|
end
|
|
873
970
|
|
|
874
971
|
# Unpins this session from the pinned server or connection, if the session was pinned
|
|
@@ -884,14 +981,12 @@ module Mongo
|
|
|
884
981
|
# @api private
|
|
885
982
|
def unpin_maybe(error, connection = nil)
|
|
886
983
|
if !within_states?(Session::NO_TRANSACTION_STATE) &&
|
|
887
|
-
|
|
888
|
-
then
|
|
984
|
+
error.label?('TransientTransactionError')
|
|
889
985
|
unpin(connection)
|
|
890
986
|
end
|
|
891
987
|
|
|
892
988
|
if committing_transaction? &&
|
|
893
|
-
|
|
894
|
-
then
|
|
989
|
+
error.label?('UnknownTransactionCommitResult')
|
|
895
990
|
unpin(connection)
|
|
896
991
|
end
|
|
897
992
|
end
|
|
@@ -922,9 +1017,7 @@ module Mongo
|
|
|
922
1017
|
# @api private
|
|
923
1018
|
def add_start_transaction!(command)
|
|
924
1019
|
command.tap do |c|
|
|
925
|
-
if starting_transaction?
|
|
926
|
-
c[:startTransaction] = true
|
|
927
|
-
end
|
|
1020
|
+
c[:startTransaction] = true if starting_transaction?
|
|
928
1021
|
end
|
|
929
1022
|
end
|
|
930
1023
|
|
|
@@ -952,7 +1045,7 @@ module Mongo
|
|
|
952
1045
|
#
|
|
953
1046
|
# @since 2.6.0
|
|
954
1047
|
# @api private
|
|
955
|
-
def add_txn_opts!(command,
|
|
1048
|
+
def add_txn_opts!(command, _read, context)
|
|
956
1049
|
command.tap do |c|
|
|
957
1050
|
# The read concern should be added to any command that starts a transaction.
|
|
958
1051
|
if starting_transaction?
|
|
@@ -975,27 +1068,23 @@ module Mongo
|
|
|
975
1068
|
if rc.nil? || rc.empty?
|
|
976
1069
|
c.delete(:readConcern)
|
|
977
1070
|
else
|
|
978
|
-
c[:readConcern
|
|
1071
|
+
c[:readConcern] = Options::Mapper.transform_values_to_strings(rc)
|
|
979
1072
|
end
|
|
980
1073
|
end
|
|
981
1074
|
|
|
982
1075
|
# We need to send the read concern level as a string rather than a symbol.
|
|
983
|
-
if c[:readConcern]
|
|
984
|
-
c[:readConcern] = Options::Mapper.transform_values_to_strings(c[:readConcern])
|
|
985
|
-
end
|
|
1076
|
+
c[:readConcern] = Options::Mapper.transform_values_to_strings(c[:readConcern]) if c[:readConcern]
|
|
986
1077
|
|
|
987
|
-
if c[:commitTransaction]
|
|
988
|
-
|
|
989
|
-
c[:maxTimeMS] = max_time_ms
|
|
990
|
-
end
|
|
1078
|
+
if c[:commitTransaction] && (max_time_ms = txn_options[:max_commit_time_ms])
|
|
1079
|
+
c[:maxTimeMS] = max_time_ms
|
|
991
1080
|
end
|
|
992
1081
|
|
|
993
1082
|
# The write concern should be added to any abortTransaction or commitTransaction command.
|
|
994
|
-
if
|
|
1083
|
+
if c[:abortTransaction] || c[:commitTransaction]
|
|
995
1084
|
if @already_committed
|
|
996
1085
|
wc = BSON::Document.new(c[:writeConcern] || txn_write_concern || {})
|
|
997
1086
|
wc.merge!(w: :majority)
|
|
998
|
-
wc[:wtimeout] ||=
|
|
1087
|
+
wc[:wtimeout] ||= 10_000
|
|
999
1088
|
c[:writeConcern] = wc
|
|
1000
1089
|
elsif txn_write_concern
|
|
1001
1090
|
c[:writeConcern] ||= txn_write_concern
|
|
@@ -1008,12 +1097,10 @@ module Mongo
|
|
|
1008
1097
|
end
|
|
1009
1098
|
|
|
1010
1099
|
# Ignore wtimeout if csot
|
|
1011
|
-
if context&.csot?
|
|
1012
|
-
c[:writeConcern]&.delete(:wtimeout)
|
|
1013
|
-
end
|
|
1100
|
+
c[:writeConcern]&.delete(:wtimeout) if context&.csot?
|
|
1014
1101
|
|
|
1015
1102
|
# We must not send an empty (server default) write concern.
|
|
1016
|
-
c.delete(:writeConcern) if c[:writeConcern]
|
|
1103
|
+
c.delete(:writeConcern) if c[:writeConcern] && c[:writeConcern].empty?
|
|
1017
1104
|
end
|
|
1018
1105
|
end
|
|
1019
1106
|
|
|
@@ -1035,7 +1122,7 @@ module Mongo
|
|
|
1035
1122
|
end
|
|
1036
1123
|
end
|
|
1037
1124
|
|
|
1038
|
-
# Ensure that the read preference of a command primary.
|
|
1125
|
+
# Ensure that the read preference of a command is primary.
|
|
1039
1126
|
#
|
|
1040
1127
|
# @example
|
|
1041
1128
|
# session.validate_read_preference!(command)
|
|
@@ -1051,11 +1138,21 @@ module Mongo
|
|
|
1051
1138
|
|
|
1052
1139
|
mode = command['$readPreference']['mode'] || command['$readPreference'][:mode]
|
|
1053
1140
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
)
|
|
1058
|
-
|
|
1141
|
+
return unless mode && mode != 'primary'
|
|
1142
|
+
|
|
1143
|
+
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
1144
|
+
"read preference in a transaction must be primary (requested: #{mode})"
|
|
1145
|
+
)
|
|
1146
|
+
end
|
|
1147
|
+
|
|
1148
|
+
# Reverts the session state to STARTING_TRANSACTION_STATE.
|
|
1149
|
+
# Called before retrying the first command in a transaction so that
|
|
1150
|
+
# startTransaction: true is preserved on the retry.
|
|
1151
|
+
# @api private
|
|
1152
|
+
def revert_to_starting_transaction!
|
|
1153
|
+
return unless within_states?(TRANSACTION_IN_PROGRESS_STATE)
|
|
1154
|
+
|
|
1155
|
+
@state = STARTING_TRANSACTION_STATE
|
|
1059
1156
|
end
|
|
1060
1157
|
|
|
1061
1158
|
# Update the state of the session due to a (non-commit and non-abort) operation being run.
|
|
@@ -1085,8 +1182,8 @@ module Mongo
|
|
|
1085
1182
|
# @since 2.5.0
|
|
1086
1183
|
# @api private
|
|
1087
1184
|
def validate!(client)
|
|
1088
|
-
check_matching_cluster!(client)
|
|
1089
1185
|
check_if_ended!
|
|
1186
|
+
check_matching_cluster!(client)
|
|
1090
1187
|
self
|
|
1091
1188
|
end
|
|
1092
1189
|
|
|
@@ -1110,10 +1207,8 @@ module Mongo
|
|
|
1110
1207
|
end
|
|
1111
1208
|
@server_session.set_last_use!
|
|
1112
1209
|
|
|
1113
|
-
if doc = result.reply && result.reply.documents.first
|
|
1114
|
-
|
|
1115
|
-
self.recovery_token = doc[:recoveryToken]
|
|
1116
|
-
end
|
|
1210
|
+
if (doc = result.reply && result.reply.documents.first) && doc[:recoveryToken]
|
|
1211
|
+
self.recovery_token = doc[:recoveryToken]
|
|
1117
1212
|
end
|
|
1118
1213
|
|
|
1119
1214
|
result
|
|
@@ -1130,11 +1225,11 @@ module Mongo
|
|
|
1130
1225
|
#
|
|
1131
1226
|
# @since 2.5.0
|
|
1132
1227
|
def advance_operation_time(new_operation_time)
|
|
1133
|
-
if @operation_time
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1228
|
+
@operation_time = if @operation_time
|
|
1229
|
+
[ @operation_time, new_operation_time ].max
|
|
1230
|
+
else
|
|
1231
|
+
new_operation_time
|
|
1232
|
+
end
|
|
1138
1233
|
end
|
|
1139
1234
|
|
|
1140
1235
|
# If not already set, populate a session objects's server_session by
|
|
@@ -1144,9 +1239,7 @@ module Mongo
|
|
|
1144
1239
|
#
|
|
1145
1240
|
# @api private
|
|
1146
1241
|
def materialize_if_needed
|
|
1147
|
-
if ended?
|
|
1148
|
-
raise Error::SessionEnded
|
|
1149
|
-
end
|
|
1242
|
+
raise Error::SessionEnded if ended?
|
|
1150
1243
|
|
|
1151
1244
|
return unless implicit? && !@server_session
|
|
1152
1245
|
|
|
@@ -1157,9 +1250,7 @@ module Mongo
|
|
|
1157
1250
|
|
|
1158
1251
|
# @api private
|
|
1159
1252
|
def materialized?
|
|
1160
|
-
if ended?
|
|
1161
|
-
raise Error::SessionEnded
|
|
1162
|
-
end
|
|
1253
|
+
raise Error::SessionEnded if ended?
|
|
1163
1254
|
|
|
1164
1255
|
!@server_session.nil?
|
|
1165
1256
|
end
|
|
@@ -1174,9 +1265,7 @@ module Mongo
|
|
|
1174
1265
|
# @since 2.5.0
|
|
1175
1266
|
# @api private
|
|
1176
1267
|
def next_txn_num
|
|
1177
|
-
if ended?
|
|
1178
|
-
raise Error::SessionEnded
|
|
1179
|
-
end
|
|
1268
|
+
raise Error::SessionEnded if ended?
|
|
1180
1269
|
|
|
1181
1270
|
@server_session.next_txn_num
|
|
1182
1271
|
end
|
|
@@ -1190,20 +1279,39 @@ module Mongo
|
|
|
1190
1279
|
#
|
|
1191
1280
|
# @since 2.6.0
|
|
1192
1281
|
def txn_num
|
|
1193
|
-
if ended?
|
|
1194
|
-
raise Error::SessionEnded
|
|
1195
|
-
end
|
|
1282
|
+
raise Error::SessionEnded if ended?
|
|
1196
1283
|
|
|
1197
1284
|
@server_session.txn_num
|
|
1198
1285
|
end
|
|
1199
1286
|
|
|
1287
|
+
# @return [ BSON::Timestamp | nil ] The snapshot time for this session.
|
|
1288
|
+
# nil if the session is not a snapshot session, or if it is a snapshot
|
|
1289
|
+
# session for which no :snapshot_time option was provided and no read
|
|
1290
|
+
# has yet captured atClusterTime from the server.
|
|
1291
|
+
attr_reader :snapshot_timestamp
|
|
1292
|
+
|
|
1293
|
+
# Sets the snapshot time for the session. Once set, subsequent
|
|
1294
|
+
# assignments are ignored: snapshotTime is established at most once per
|
|
1295
|
+
# session, either from the :snapshot_time option at construction or from
|
|
1296
|
+
# the atClusterTime returned by the first find/aggregate/distinct
|
|
1297
|
+
# response. This keeps the property effectively read-only for callers,
|
|
1298
|
+
# per the snapshot-sessions spec rationale.
|
|
1299
|
+
#
|
|
1200
1300
|
# @api private
|
|
1201
|
-
|
|
1301
|
+
def snapshot_timestamp=(value)
|
|
1302
|
+
@snapshot_timestamp ||= value
|
|
1303
|
+
end
|
|
1202
1304
|
|
|
1203
1305
|
# @return [ Integer | nil ] The deadline for the current transaction, if any.
|
|
1204
1306
|
# @api private
|
|
1205
1307
|
attr_reader :with_transaction_deadline
|
|
1206
1308
|
|
|
1309
|
+
# @return [ Boolean ] Whether we are currently inside a with_transaction block.
|
|
1310
|
+
# @api private
|
|
1311
|
+
def inside_with_transaction?
|
|
1312
|
+
@inside_with_transaction
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1207
1315
|
private
|
|
1208
1316
|
|
|
1209
1317
|
# Get the read concern the session will use when starting a transaction.
|
|
@@ -1229,7 +1337,8 @@ module Mongo
|
|
|
1229
1337
|
return unless within_states?(NO_TRANSACTION_STATE)
|
|
1230
1338
|
|
|
1231
1339
|
raise Mongo::Error::InvalidTransactionOperation.new(
|
|
1232
|
-
Mongo::Error::InvalidTransactionOperation::NO_TRANSACTION_STARTED
|
|
1340
|
+
Mongo::Error::InvalidTransactionOperation::NO_TRANSACTION_STARTED
|
|
1341
|
+
)
|
|
1233
1342
|
end
|
|
1234
1343
|
|
|
1235
1344
|
def txn_write_concern
|
|
@@ -1240,25 +1349,23 @@ module Mongo
|
|
|
1240
1349
|
# Returns causal consistency document if the last operation time is
|
|
1241
1350
|
# known and causal consistency is enabled, otherwise returns nil.
|
|
1242
1351
|
def causal_consistency_doc
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
nil
|
|
1247
|
-
end
|
|
1352
|
+
return unless operation_time && causal_consistency?
|
|
1353
|
+
|
|
1354
|
+
{ afterClusterTime: operation_time }
|
|
1248
1355
|
end
|
|
1249
1356
|
|
|
1250
1357
|
def causal_consistency?
|
|
1251
|
-
@causal_consistency ||=
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1358
|
+
@causal_consistency ||= if @options.key?(:causal_consistency)
|
|
1359
|
+
!!@options[:causal_consistency]
|
|
1360
|
+
else
|
|
1361
|
+
true
|
|
1362
|
+
end
|
|
1256
1363
|
end
|
|
1257
1364
|
|
|
1258
1365
|
def set_operation_time(result)
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1366
|
+
return unless result && result.operation_time
|
|
1367
|
+
|
|
1368
|
+
@operation_time = result.operation_time
|
|
1262
1369
|
end
|
|
1263
1370
|
|
|
1264
1371
|
def check_if_ended!
|
|
@@ -1266,40 +1373,34 @@ module Mongo
|
|
|
1266
1373
|
end
|
|
1267
1374
|
|
|
1268
1375
|
def check_matching_cluster!(client)
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1376
|
+
return unless cluster != client.cluster
|
|
1377
|
+
|
|
1378
|
+
raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG)
|
|
1272
1379
|
end
|
|
1273
1380
|
|
|
1274
1381
|
def check_transactions_supported!
|
|
1275
|
-
raise Mongo::Error::TransactionsNotSupported,
|
|
1276
|
-
|
|
1277
|
-
cluster.next_primary.with_connection do |conn|
|
|
1278
|
-
if cluster.replica_set? && !conn.features.transactions_enabled?
|
|
1279
|
-
raise Mongo::Error::TransactionsNotSupported, "server version is < 4.0"
|
|
1280
|
-
end
|
|
1281
|
-
if cluster.sharded? && !conn.features.sharded_transactions_enabled?
|
|
1282
|
-
raise Mongo::Error::TransactionsNotSupported, "sharded transactions require server version >= 4.2"
|
|
1283
|
-
end
|
|
1284
|
-
end
|
|
1382
|
+
raise Mongo::Error::TransactionsNotSupported, 'standalone topology' if cluster.single?
|
|
1285
1383
|
end
|
|
1286
1384
|
|
|
1287
1385
|
def operation_timeouts(opts)
|
|
1288
1386
|
{
|
|
1289
|
-
inherited_timeout_ms: @client.timeout_ms
|
|
1387
|
+
inherited_timeout_ms: @with_transaction_timeout_ms || @client.timeout_ms
|
|
1290
1388
|
}.tap do |result|
|
|
1291
|
-
if @
|
|
1292
|
-
if
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
result[:operation_timeout_ms] = default_timeout_ms
|
|
1389
|
+
if @inside_with_transaction
|
|
1390
|
+
if opts[:timeout_ms]
|
|
1391
|
+
raise Mongo::Error::InvalidTransactionOperation,
|
|
1392
|
+
'timeoutMS cannot be overridden inside a withTransaction callback'
|
|
1296
1393
|
end
|
|
1394
|
+
elsif timeout_ms = opts[:timeout_ms]
|
|
1395
|
+
result[:operation_timeout_ms] = timeout_ms
|
|
1396
|
+
elsif default_timeout_ms = options[:default_timeout_ms]
|
|
1397
|
+
result[:operation_timeout_ms] = default_timeout_ms
|
|
1297
1398
|
end
|
|
1298
1399
|
end
|
|
1299
1400
|
end
|
|
1300
1401
|
|
|
1301
1402
|
def calculate_with_transaction_deadline(opts)
|
|
1302
|
-
calc =
|
|
1403
|
+
calc = lambda { |timeout|
|
|
1303
1404
|
if timeout == 0
|
|
1304
1405
|
0
|
|
1305
1406
|
else
|
|
@@ -1322,5 +1423,36 @@ module Mongo
|
|
|
1322
1423
|
Utils.monotonic_time >= deadline
|
|
1323
1424
|
end
|
|
1324
1425
|
end
|
|
1426
|
+
|
|
1427
|
+
# Exponential backoff settings for with_transaction retries.
|
|
1428
|
+
BACKOFF_INITIAL = 0.005
|
|
1429
|
+
BACKOFF_MAX = 0.5
|
|
1430
|
+
private_constant :BACKOFF_INITIAL, :BACKOFF_MAX
|
|
1431
|
+
|
|
1432
|
+
def backoff_seconds_for_retry(transaction_attempt)
|
|
1433
|
+
exponential = BACKOFF_INITIAL * (1.5**(transaction_attempt - 1))
|
|
1434
|
+
Random.rand * [ exponential, BACKOFF_MAX ].min
|
|
1435
|
+
end
|
|
1436
|
+
|
|
1437
|
+
def backoff_would_exceed_deadline?(deadline, backoff_seconds)
|
|
1438
|
+
return false if deadline.zero?
|
|
1439
|
+
|
|
1440
|
+
Utils.monotonic_time + backoff_seconds >= deadline
|
|
1441
|
+
end
|
|
1442
|
+
|
|
1443
|
+
# Implements makeTimeoutError(lastError) from the transactions-convenient-api spec.
|
|
1444
|
+
# In CSOT mode raises TimeoutError with last_error's message and labels copied.
|
|
1445
|
+
# In non-CSOT mode re-raises last_error directly.
|
|
1446
|
+
def make_timeout_error_from(last_error, timeout_message)
|
|
1447
|
+
if @with_transaction_timeout_ms
|
|
1448
|
+
timeout_error = Mongo::Error::TimeoutError.new("#{timeout_message}: #{last_error}")
|
|
1449
|
+
if last_error.respond_to?(:labels)
|
|
1450
|
+
last_error.labels.each { |label| timeout_error.add_label(label) }
|
|
1451
|
+
end
|
|
1452
|
+
raise timeout_error
|
|
1453
|
+
end
|
|
1454
|
+
|
|
1455
|
+
raise last_error
|
|
1456
|
+
end
|
|
1325
1457
|
end
|
|
1326
1458
|
end
|